我对仓库定义的限制和应该留给服务的内容感到困惑。仓库只能创建与数据库中表匹配的简单实体,还是可以创建由这些实体组合而成的复杂自定义对象?
换句话说:服务是否应该在仓库上进行各种 Linq to SQL 查询?还是所有查询都应该在仓库中预定义,业务逻辑只需决定调用哪个方法?
我对仓库定义的限制和应该留给服务的内容感到困惑。仓库只能创建与数据库中表匹配的简单实体,还是可以创建由这些实体组合而成的复杂自定义对象?
换句话说:服务是否应该在仓库上进行各种 Linq to SQL 查询?还是所有查询都应该在仓库中预定义,业务逻辑只需决定调用哪个方法?
你提出的问题目前正在开发者社区中引起广泛讨论 - 参见Should my repository expose IQueryable? 的后续评论。
仓储库可以 - 也应该 - 创建包含多个关联实体的复杂组合对象。在领域驱动设计中,这些被称为聚合根 - 关联对象的集合,组织成某种有凝聚力的结构。你的代码不需要分别调用GetCustomer()
、GetOrdersForCustomer()
、GetInvoicesForCustomer()
,只需调用myCustomerRepository.Load(customerId)
,就会返回一个深层次的客户对象,其中这些属性已经被初始化了。我还要补充一点,如果你是基于特定数据库表返回单独对象,那么这是一种完全有效的方法,但它并不是真正的仓储库 per sé - 它只是一个数据访问层。
一方面,有一个有说服力的观点认为,Linq-to-SQL 对象具有“智能”属性和延迟执行(即不会加载 Customer.Orders,直到你实际使用它)等特点,因此是仓储库模式的完全有效实现,因为你实际上并没有运行数据库代码,而是运行 LINQ 语句(然后由底层的 LINQ 提供程序将其转换为 DB 代码)。
另一方面,正如 Matt Briggs 的帖子指出的那样,L2S 与您的数据库结构相当紧密地耦合在一起(每个表一个类),并且有一些限制(例如,没有多对多映射) - 因此,您可能最好在仓储库中使用 L2S 进行数据访问,但然后将 L2S 对象映射到自己的领域模型对象并返回这些对象。
一个仓库应该是应用程序中唯一知道数据访问技术的部分。因此,它不应该返回由L2S生成的对象,而是将这些属性映射到您自己的模型对象。
如果您正在使用这种模式,您可能需要重新考虑L2S。它为您生成了一个数据访问层,但并没有真正处理阻抗不匹配,您必须手动处理。如果您查看类似NHibernate的东西,那么这种映射是以更强大的方式完成的。 L2S更适合于两层应用程序,其中您需要一个快速且简单的DAL,可以轻松扩展。