在使用Entity Framework Code First时,组织上应该把常见查询放在哪里?

24
我正在使用EF 4.1 Code First布置一个新的数据层,从旧的自制数据层进行迁移。
我设置了两个程序集,一个用于我的上下文,另一个用于所有POCO Code First类。例如,我有一些业务逻辑,比如针对一个表(或几个表)的查询,在多个不同的地方使用。那么这些逻辑应该放在哪里呢?
它不能放在POCO类中,因为它连接了几个表,所以需要一个上下文。它可以放在上下文中,但是这个上下文会变得臃肿,并且包含数百个没有组织的查询。是否有一种通用的模式或安排来处理所有的业务逻辑呢?
3个回答

76

看起来仓储模式是万能的解决方案... 仓储模式并不是银弹!

我每天都在使用仓储模式与 EF,因为几个月前开始我的当前项目时,它似乎是被推荐的解决方案。我的结论:

  • 仓储模式使与 EF 的交互更加困难。只需浏览与 EF 标签相关的问题,您就会看到必须直接处理上下文、changetracker 等复杂性。
  • 通用仓储库适用于 CRUD 操作,但不适用于真正的 DDD 场景。一旦您的仓储库与聚合根(DDD)一起工作,则通用方法失败。
  • 单元测试根本行不通,因为普遍的想法是您将模拟存储库,并在没有依赖于 EF 和数据库的情况下测试上层。一旦您公开 IQueryable,Linq-to-entities 只是 Linq-to-objects 的子集,模拟不能处理引用完整性,因此我多次看到绿色单元测试和运行时异常。使用 EF 的正确测试方法是集成测试。模拟存储库仅用于测试与数据访问无关的实际业务逻辑。如果您没有针对访问或持久化数据的业务方法进行集成测试,则没有对其进行测试。
  • 公开类似 GetByXXX 的专门方法只是一个后退步骤。大多数这些方法仅用于一次。您将以类似于用于包装存储过程调用的仓储库的代码结束。许多开发人员喜欢 ORM,只是因为它们可以避免这种严格的架构。

EF 本身已经提供了仓储模式 - DbSetObjectSet 是存储库,DbContextObjectContext 是工作单元。因此,在我看来,仓储模式被过度使用。它在需要严格分层或在其方法中放置附加逻辑的大型项目中可能有用。仅因为您想封装对 EF 的访问而使用存储库通常是毫无价值的代码并只会增加复杂性。

您也可以通过相同的方式创建可重用的方法来定义查询。


8
+1 我曾经一直是 Repository 支持者,但我同意文章中提到的所有内容 - 这会让很多事情变得更加困难和不那么干净。由于这已经融入了我的当前设计,现在放弃它会很困难,但如果从头开始设计,我会三思而后行。 - BrokenGlass
3
我看到你在这里的观点,但是你没有提供替代方案?服务通过规范作为约束(Lambda)?你/你会如何设置数据访问? - Paul
2
这也是我的感觉...但你能详细说明一下你如何组织你所提出的建议“您可以以同样的方式创建定义查询的可重用方法。” - 确切地说,在哪里? - Scott Stafford
6
@Teasung: 我不处理“如果发生了什么”的情况 - 我的工作是交付现在所需的功能,而不是为未来可能发生的每种情况准备我的应用程序。一旦它发生了,我将不得不进行大量更改。ORM 是有漏洞的抽象层,如果您想充分利用其功能,您仍会在您的代码中有一些隐藏的依赖关系(这可能不是对 EF 的引用,而是按照所使用的 ORM 预期的方式建立的一些逻辑)。我看到过几个项目处理“如果”的情况,导致过度架构化的垃圾代码,而这种情况从未发生过。 - Ladislav Mrnka
听起来你的大部分观点可能会因存储库模式的实现方式而有所不同。 - Didier A.
显示剩余5条评论

4
我会使用仓储模式(Repository Pattern)。下面是使用EF code first和MVC的示例: Entity Framework 4 CTP 4 / CTP 5通用存储库模式和可单元测试性
以下是该模式的一些好文章: 考虑到您正在使用领域模型,深入了解领域驱动设计(DDD)可能也是个好主意。
以下是一些关于DDD的好文章:

2

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接