存储库模式 - 如何正确处理JOIN和复杂查询?

时间:2014-01-21 12:01:04

标签: asp.net-mvc entity-framework design-patterns domain-driven-design repository-pattern

我遇到了Repository模式的问题 - 如何在多个存储库之间执行JOIN操作。在这个项目中,我们使用MVC,EF,DDD。我已经多次知道这类问题了,我稍后会在这个问题中提到这些问题。

在通用存储库模型(IRepository)和特定存储库模型之间,我选择了特定选项,因为我将ORM(在我们的例子中为EF)视为通用存储库模式本身,因此添加另一个通用链接没有意义存储库,我们宁愿根据域需求定制存储库。

问题是我有几个(~10个)表,每个表有很多行(数百万),我需要执行JOIN,所以使用IList或IEnumerable是不可行的选项。

我的理解(和我的观点)是IQueryable不应该离开存储库("在DAL中会发生什么,应该保留在DAL中。")。暴露IQueryable并在LINQ服务中使用它会更简单,但它强烈违反了关注点的分离并破坏了存储库的作用 - 在这种情况下,服务将与存储库做同样的事情。为了选择一些,这些文章支持这种观点(或者更确切地说是信念):

To return IQueryable<T> or not return IQueryable<T>

Should I return IEnumerable<T> or IQueryable<T> from my DAL?

http://www.shawnmclean.com/blog/2011/06/iqueryable-vs-ienumerable-in-the-repository-pattern/

http://blog.ploeh.dk/2012/03/26/IQueryableTisTightCoupling/

也有类似的问题和解决方案,例如提示.Include()的How to join Multiple tables using Repository Pattern & Entity Framework?,但这不是重载表和多个表连接的选项 - 对于每个JOIN,我们使用子选择来限制实际连接的内容。

这个问题(答案和评论) - How can I query cross tables with Repository Pattern? - 基本上建议基于任务的区分:使用JOINS为查询创建一个存储库,以及&#34;常规&#34;用于操纵每个实体的存储库。

我看到我们有这些选择:

  1. 在服务中公开IQueryable并执行JOIN复杂查询;我真诚地感受到它的反模式,我不喜欢这样。
  2. 不要在这些~10个表中使用Repository并在服务中执行查询;有些文章建议使用EF就足够了(例如Is it okay to bypass the repository pattern for complex queries?),我不同意。
  3. 使用基于任务的区分,不要限制存储库1:1 repo:entity(我赞成此选项)
  4. 完全不同的东西?
  5. 那么 - 你会建议什么?一次又一次,谢谢。

1 个答案:

答案 0 :(得分:16)

  1. 意味着将持久性泄露到应用程序中 - 反模式,意大利面条代码。
  2. 它与(1)完全不同?仍然是同一个问题。
  3. 更近一点......
  4. 使用查询对象模式。将复杂查询封装在与存储库一起驻留的基于任务的对象中。它可以返回针对视图优化的DTO而不是域对象。
  5. 严重依赖QO将引导您使用名为CQRS的架构 - 命令查询责任隔离
  6. 还有一件事。实体:repo没有1:1匹配。只有聚合应该有一个存储库,而不是每个实体。