【问题标题】:IAsyncRepository or IObservableRepository for silverlight 4 + WCF Data ServicesSilverlight 4 + WCF 数据服务的 IAsyncRepository 或 IObservableRepository
【发布时间】:2011-03-18 07:22:05
【问题描述】:

更新 2:@Enigmativity 有一个绝妙的答案。我已将其实现为IObservableRepository<T>。我在下面的答案中有详细信息。


问题: 因此,我已经更改了大部分问题(请参阅编辑历史记录),如果有人对我的设计发表评论/验证/吐槽,我会很高兴。 =)

所以我的 Repos 通常是这样的:

public interface IRepository<T> where T : class
{
    T GetById(int id);
    IQueryable<T> GetAll();
    void InsertOnSubmit(T entity);
    void DeleteOnSubmit(T entity);
    int SubmitChanges();
}

但是当涉及到 Silverlight 和 WCF 数据服务时,它会因为所有的异步性而变得非常烦人的查询相关数据。我必须先异步加载父实体,然后异步查询其子实体。

所以我想出了一个IAsyncRepository,我想知道设计是否还可以,是否可以改进,(以及在这里使用 Rx 是否有意义?)

为了解决子实体问题,我计划在调用回调之前加载所有必需子实体。

我的回购看起来像:

public interface IAsyncRepository<T> where T : class
{
    void GetById(int id, Action<T> callback);
    void GetAllFromQuery(Func<MyEntities, IQueryable<Product>> funcquery,
                                             Action<IList<Calculator>> callback)
}

你可以像这样使用 repo:

productRepo.GetAllFromQuery(
    x => x.Products.Where(p => p.ID > 5),
    y => Assert.IsTrue(y.Count > 0)); //y is a IList<Product>

你们觉得呢?

问候, 基甸

【问题讨论】:

  • 只是好奇,但为什么不直接使用 WCF RIA 服务并利用它提供的开箱即用的异步加载和关联事件、验证冒泡、带外调用、变更集管理等为 POCO?
  • 真的希望我能做到这一点,但是,我已经有一个基于 WCF-Data Services 构建的应用程序,SL 应用程序不是唯一的消费者。主要消费者之一是桌面/WPF应用程序。
  • @nissan 只是想一想在 Entity Framework 4 模型上提供 RIA 服务有多难?它对 WPF 桌面应用程序也有好处吗?
  • 创建一个公开实体框架 4 的域服务是轻而易举的事。我没有尝试从 WPF 访问它,但这些人有:stackoverflow.com/questions/2551258/… 您可以通过简单的配置更改轻松地将您的域服务发布到 OData、SOAP 和 JSON。您可能至少想探索一下。
  • @Nissan 谢谢,我会检查一下,也许会在下一个 SL 应用程序中使用它,但在当前应用程序中无法使用,因为它已经编写了很多代码并且需要待更新和重构。

标签: c# silverlight repository-pattern wcf-data-services system.reactive


【解决方案1】:

只是一个快速、即兴的答案。

使用Reactive Extensions for .NET (Rx)怎么样?

然后您可以将您的存储库定义为:

public interface IObservableRepository<T> where T : class
{
    IObservable<T> GetById(int id);
    IObservable<T> GetAll(Func<IQueryable<T>, IQueryable<T>> query);
    IObservable<Unit> InsertOnSubmit(T entity);
    IObservable<Unit> DeleteOnSubmit(T entity);
    IObservable<int> SubmitChanges();
}

所有返回的 observable 都将包含单个值,但 GetAll 除外,它的值为零或多个。

Unit 类型在 Rx 世界中是 void。这只是一种不需要定义非泛型IObservable 接口的方式。

然后你会像这样查询:

IObservableRepository<Foo> repo = ...;

var foos = repo.GetAll(ts => ts.Where(t => t.Bar == "Hello"));

foos.Subscribe(foo =>
{
    // Do something asynchronously with each `Foo`.
});

可以这样提交:

var submit =
    foos
        .Select(foo => repo.InsertOnSubmit(foo)).ToArray()
        .Select(s => repo.SubmitChanges());

submit.Subscribe(result =>
{
    // handle the asynchronous result of submit.
});

这一切都是基于尝试使存储库方法尽可能接近原始方法,但在 Silverlight 方面可能值得重构如下:

public interface IObservableRepository<T> where T : class
{
    IObservable<T> GetById(int id);
    IObservable<T[]> GetAll(Func<IQueryable<T>, IQueryable<T>> query);
    IObservable<int> Submit(T[] insertsOrUpdates);
    IObservable<int> Submit(T[] insertsOrUpdates, T[] deletes);
}

现在提交会更好:

repo.Submit(foos).Subscribe(result =>
{
    // Handle asynchronous result of submit;
});

就像我说的,即兴表演。 :-)

【讨论】:

  • +1 很好的答案!!花了整个晚上来实施和测试它。它的炸弹!说真的!
  • 在下面查看我的实现:)
【解决方案2】:

更新问题太长,所以我发布了答案。

所以我是这样实现的:

public interface IObservableRepository<T, TContext>
{
    IObservable<T> GetById(int id);
    IObservable<IList<T>> GetAll(Func<TContext, IQueryable<T>> funcquery);
    IObservable<int[]> SubmitInserts(IList<T> inserts);
    IObservable<int[]> SubmitDeletes(IList<T> deletes);
    IObservable<int[]> SubmitUpdates(IList<T> updates);
    //helpers
    IObservable<int> SubmitInsert(T entity);
    IObservable<int> SubmitDelete(T entity);
    IObservable<int> SubmitUpdate(T entity);
}

一些注意事项:

  • GetAll() 需要TContext,实现将具有实体框架DataServiceContext,它允许您执行以下操作:

    var foos = repo.GetAll(ts => ts.Where(t => t.Bar == "Hello"));
    //ts is a DataContext passed here by GetAll();
    
  • 标记为//helpers 的方法只是调用其他采用数组的方法。
  • WCF 数据服务+实体框架的 CRUD 函数的实际返回类型是 DataServiceResponse。我所做的是遍历它们并返回 Http 状态代码。因此,为 CRUD 方法返回的整数是 Http 状态代码。
  • 加载子实体时,我只是急切地加载它们:

    context.Products.Expand("Child").Expand("Child2");
    

我基本上可以这样使用:

productRepo.GetById(3).Subscribe(x => /* Do something with product x*/ );
productRepo.SubmitUpdate(product)
         .Subscribe(r => /*return code should be 204 (http) 201 for insert */);
//same for insert and delete

请告诉我是否应该将实际的实现放在这里。

任何关于这方面的 cmet 都会被很好地接受 =)

谢谢

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-06-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-09-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多