渴望加载和存储库模式

Arn*_*psa 21 repository-pattern eager-loading

我想知道如何在使用Repository模式时正确处理复杂对象图的急切加载问题.我猜这不是ORM特有的问题.

第一次尝试:

public interface IProductRepository : IRepository<Product>
{
  Product GetById(int id);
  IProductRepository WithCustomers();
}
Run Code Online (Sandbox Code Playgroud)

这样可以正常工作,但这将涉及一直重复自己(在各地的存储库实现中编写自定义'With'方法).

下一步方法:

public interface IRepository<T> where T : IAggregateRoot
{
  ...
  void With(Expression<Func<T, object>> propToExpand);
}
Run Code Online (Sandbox Code Playgroud)

With 方法会将一个项目添加到私有集合中,稍后将使用该项目来查找在检索必要的实体时应该急切加载哪些道具.

这种工作很好.但我不喜欢用法:

productRepository.With(x=>x.Customer);
productRepository.With(x=>x.Price);
productRepository.With(x=>x.Manufacturer);
var product = productRepository.GetById(id);
Run Code Online (Sandbox Code Playgroud)

基本上 - 问题是没有链接.我希望它是这样的:

var product = productRepository
  .With(x=>x.Customer)
  .With(x=>x.Price)
  .With(x=>x.Manufacturer)
  .GetById(id);
Run Code Online (Sandbox Code Playgroud)

我无法做到这一点.即使我可以 - 我不确定这个解决方案是否优雅.

这导致我缺少一些基本的想法(在任何地方缺乏例子).有没有不同的方法来处理这个?什么是最佳做法?

Max*_*Max 9

有趣的问题,我相信你不是第一个遇到麻烦的人(我绝对有).

对我来说,真正的问题是:你想在哪里放置你急切的加载逻辑?

在客户端代码中的存储库之外

var product = productRepository
.With(x=>x.Customer)
.With(x=>x.Price)
.With(x=>x.Manufacturer)
.GetById(id);
Run Code Online (Sandbox Code Playgroud)

我不认为这是一个很好的软件设计:如果这样的结构分散在你的整个应用程序中,它看起来可能导致"一千次切割死亡".

或者在存储库中.例:

interface IProductRepository {
    Product GetById(int id);
    Product GetByIdWithCustomers(int i);
}
Run Code Online (Sandbox Code Playgroud)

所以你的客户端代码看起来像这样:

var product = productRepository.GetByIdWithCustomers(id);
Run Code Online (Sandbox Code Playgroud)

通常我会创建一个BaseRepository,它只定义了基本的CRUD操作:

public class BaseRepository<TEntity, TPrimaryKey> {
    public void Save(TEntity entity) { ... }
    public void Delete(TEntity entity) { ... }
    public TEntity Load(TPrimaryKey id) { ... } // just gets the entity by primary key
}
Run Code Online (Sandbox Code Playgroud)

然后我扩展这个基类/接口,以便提供获取域对象的特定方法.你的方法似乎有点类似的方向.

public class MediaRepository : BaseRepository<Media, int> {
    public long CountMediaWithCategories() { ... }
    public IList<Media> MediaInCategories(IList<Category> categories) { .... }
}
Run Code Online (Sandbox Code Playgroud)

好处:所有ORM东西(急切加载配置,获取深度等)都封装在Repository类中,客户端代码只获取结果集.

我尝试使用非常通用的存储库,就像你正在尝试的那样,但我最终为我的域对象编写了特定的查询和存储库.

  • 是啊.我认为外面的急切加载策略也很糟糕.但我不希望我的方法名称看起来像`GetByIdWithSomethingWithSomethingWithSomethingWithSomethingWithSomething ...`.有这样的情况. (2认同)