我对在存储库中定义的内容以及留给服务的内容的限制感到困惑。存储库应该只创建与数据库中的表匹配的简单实体,还是可以创建具有这些实体组合的复杂自定义对象?
换句话说:服务是否应该在存储库上进行各种 Linq to SQL 查询?还是应该在存储库中预定义所有查询,而业务逻辑只是决定调用哪个方法?
我对在存储库中定义的内容以及留给服务的内容的限制感到困惑。存储库应该只创建与数据库中的表匹配的简单实体,还是可以创建具有这些实体组合的复杂自定义对象?
换句话说:服务是否应该在存储库上进行各种 Linq to SQL 查询?还是应该在存储库中预定义所有查询,而业务逻辑只是决定调用哪个方法?
实际上,您在这里提出了一个问题,该问题目前在开发人员社区中引起了很多讨论 - 请参阅我的存储库是否应该公开 IQueryable的后续评论?
存储库可以并且应该创建包含多个关联实体的复杂组合对象。在领域驱动设计中,这些被称为聚合——相关对象的集合组织成某种内聚的结构。您的代码不必单独调用GetCustomer()
, GetOrdersForCustomer()
,GetInvoicesForCustomer()
您只需调用myCustomerRepository.Load(customerId)
,就可以返回一个具有已实例化属性的深层客户对象。我还应该补充一点,如果您基于特定的数据库表返回单个对象,那么这是一种完全有效的方法,但它并不是真正的存储库——它只是一个数据访问层。
一方面,有一个令人信服的论点,即具有“智能”属性和延迟执行(即在您实际使用之前不加载 Customer.Orders)的 Linq-to-SQL 对象是存储库模式的完全有效实现,因为您实际上并没有运行数据库代码,所以您正在运行 LINQ 语句(然后由底层 LINQ 提供程序将其转换为 DB 代码)
另一方面,正如 Matt Briggs 的帖子所指出的,L2S 与您的数据库结构紧密耦合(每个表一个类)并且有局限性(例如,没有多对多映射) - 您最好使用 L2S用于存储库中的数据访问,然后将 L2S 对象映射到您自己的域模型对象并返回这些对象。
存储库应该是您的应用程序中唯一了解您的数据访问技术的部分。所以它根本不应该返回由 L2S 生成的对象,而是将这些属性映射到您自己的模型对象。
如果您正在使用这种模式,您可能需要重新考虑 L2S。它为您生成了一个数据访问层,但并不能真正处理阻抗不匹配,您必须手动进行。如果您查看 NHibernate 之类的东西,则该映射是以更健壮的方式完成的。L2S 更适用于 2 层应用程序,在这种应用程序中,您需要一个可以轻松扩展的快速而肮脏的 DAL。
如果您使用的是 LINQ,那么我认为存储库应该是您的 LINQ 语法的容器。这使您可以从模型对象接口中对数据库访问例程进行一定程度的抽象。正如上面 Dylan 提到的,对此事还有其他看法,有些人喜欢返回 IQueryable,以便他们可以在存储库之后继续查询数据库。只要您清楚自己的应用程序标准,这两种方法都没有错。 这里有更多关于我用于 LINQ 存储库的最佳实践的信息。