是否可以绕过复杂查询的存储库模式?

时间:2011-09-03 07:06:40

标签: design-patterns domain-driven-design repository

这是我对DDD的理解:

  • 严格的存储库模式应该只实现get(),delete()和create(),以及get()的变体,可以搜索或检索整个集合
  • 每个聚合根通常都有一个存储库

(来自研究,我知道那些不是普遍接受的规范)

这里的问题是如何实现涉及许多聚合根的复杂查询。例如,我们有两个聚合根 - 产品和用户。如果我正在做一个列出用户购买的产品的页面,那么我有一个跨用户聚合和产品聚合的查询。

如何实施此查询?

  1. 我现在正在做的事实上是拥有此查询的存储库和具有相关功能的查询(有些人会不同意并说存储库不是查询层)。

  2. 仅使用产品和用户的存储库,获取所有记录并在内存中执行所有操作(这听起来不对)

  3. 让查询(LINQ或SQL)在服务中,而不是使用与聚合相关联的存储库。

  4. 还有其他方法吗?

3 个答案:

答案 0 :(得分:16)

  

严格的存储库模式应该只实现get(),delete()   和create(),也许是get()的变体,可以搜索或者搜索   检索整个集合

存储库界面是您网域的一部分,应尽可能基于Ubiquitous Language。所有存储库都是不同的,就像所有聚合都不同一样。严格,generic repositories是CRUD过度概括,可能会降低代码表达能力。 'Create'方法也不属于Repository,因为对象生命周期的开始通常由Factory或Object本身处理。当你想要保留现有对象时,“添加”似乎是一个更好的名称,因为存储库具有集合语义。

  

这里的问题是如何实现涉及的复杂查询   许多聚合根。例如,我们有两个聚合根 -   产品和用户。如果我正在做一个列出产品用户的页面   已经购买,然后我有一个跨越用户的查询   聚合和产品聚合。

在这种情况下,您只需要听取业务要求,我强调了我认为最重要的部分。基于它看起来你需要:

Products products = /* get Products repository implementation */;
IList<Product> res = products.BoughtByUser(User user);

组织这样的代码的想法是尽可能地匹配业务需求和无处不在的语言。存储库接口的命名也很重要,我更喜欢产品 AllProducts 而不是 ProductsRepository 。 PhilCalçado对此主题有very good article,强烈推荐。

How should this query be implemented?

此查询没有什么特别之处,它可以像Products存储库中的所有其他查询一样实现。查询本身对域是隐藏的,因为存储库实现属于数据访问层。数据访问可以实现任何查询,因为它对所有聚合及其关系有深入的了解。此时它只是一个Hibernate或SQL问题。

答案 1 :(得分:14)

首先,很少针对Aggregate Roots进行查询。它们是针对数据完成的,只返回数据。存储库是在应用程序层(命令等)代码中使用的持久性的非常方便的抽象。我们需要它们,因为我们希望能够在不需要数据库的情况下测试该层。这就是为什么存储库越小越好 - 它更容易嘲笑它。

我倾向于使用专门的Finder对象,允许我的UI查询数据存储。我甚至将我的Finders放在UI层中。问题是,每次UI更改时它们都会发生变化,因此最好将它们组合在一起。您不希望在存储库中放置查询方法的另一个好理由是,存储库是您域中的一部分,是您无处不在的语言。您不希望使用易于生存和快速变化的UI概念来污染它们。

前段时间我写了一篇博客文章解释这个概念。你可以找到它here

答案 2 :(得分:-5)

只需将其放入存储库类即可。它是一个Get,可能在ProductRepository中,因为它正在返回它。 GetProductsByUser(int UserID)。或者如果你有一个n层体系结构,那么它可以在服务方法中。

我一直认为存储库是放置任何数据库访问方法的地方,因为这个想法是将数据库代码与其他所有内容分开。

相关问题