【问题标题】:DDD - How to implement high-performing repositories for searchingDDD - 如何实现用于搜索的高性能存储库
【发布时间】:2011-01-07 01:46:19
【问题描述】:

我有一个关于 DDD 和存储库模式的问题。

假设我有一个 Customer 聚合根的 Customer 存储库。 Get & Find 方法返回完全填充的聚合,其中包括地址等对象。一切都很好。但是当用户在 UI 中搜索客户时,我只需要一个聚合的“摘要”——只是一个带有摘要信息的平面对象。

我可以解决这个问题的一种方法是正常调用存储库上的 find 方法,然后在应用程序层中,将每个客户聚合映射到 CustomerSearchResult / CustomerInfo DTO,然后将它们发送回客户端。

但我的问题是性能;每个 Customer 聚合可能需要多个查询来填充所有关联。因此,如果我的搜索条件与 50 个客户匹配,那么对于可能检索我什至不需要的数据的数据库来说,这将是一个巨大的打击。

另一个问题是,我可能希望包含有关客户的汇总数据,这些数据超出了客户的聚合根边界,例如最​​后一次下订单的日期。 Order 有它自己的聚合,因此要获取客户的订单信息,我必须调用 OrderRepository,这也会降低性能。

所以现在我想我有两个选择:

  1. 向 CustomerRepository 添加一个额外的 Find 方法,该方法通过执行一个有效的查询返回这些摘要对象的列表。

  2. 创建一个专门构建的只读 CustomerInfoRepository,它只具有 1 中描述的查找方法。

但这两种感觉我都在违背 DDD 的原则。我的存储库继承自一个通用基础:Repository where T : IAggregateRoot。这些摘要信息对象不是聚合,并且与 T 的类型不同,因此 #1 确实违背了设计。

也许对于#2,我会创建一个没有 IAggregateRoot 约束的抽象 SearchRepository?

在我的领域中有很多类似的场景。

您将如何实施此方案?

谢谢, 戴夫

更新

阅读 Theo 的回答后,我想我会选择选项 #2,并在我的基础架构中创建一个专门针对这些场景的 SearchRepository。然后,应用层(WCF 服务)可以调用这些存储库,这些存储库直接填充摘要 DTO,而不是将域实体映射到 DTO。

**** 更新 2 ****

虽然我一年多前问过这个问题,但我想我只是补充一下,我已经发现了旨在解决这个确切问题的 CQRS。 Udi Dahan (http://www.udidahan.com/) 和 Greg Young (http://codebetter.com/gregyoung/) 写了很多关于它的文章。如果您使用 DDD 创建分布式应用程序,CQRS 适合您!

【问题讨论】:

    标签: c# .net domain-driven-design repository-pattern ddd-repositories


    【解决方案1】:

    我认为您只想显示汇总信息。这些汇总信息位不是领域模型的实体或值对象。它们只是信息,仅此而已。

    类似于显示报告信息。如果我处理这样的事情,我不会坚持纯粹的 DDD 方法。您建议的选项没问题,因为它可以完成您的工作。 DDD 不应被视为教条。创造性思考。放宽一点 DDD。

    但请注意,您只是在模型之外创建信息值以用于显示目的。因此,如果用户选择某位信息对其进行一些操作(在域模型中定义),您需要从信息值中提取标识符并从存储库中提取实体/值对象/聚合。

    我强烈推荐这个视频:Eric Evans: What I've learned about DDD since the book。如果你读了他的书,你真的应该看到整个视频。在大约 30:00 的时间密切关注 Eric Evans 本人谈论聚合并提到您当前遇到的问题。

    【讨论】:

    • 你是对的,它们既不是实体也不是值对象。我想我真正要问的是,这些摘要对象在域中的什么位置?我认为答案是:他们没有。就像您说的,它们仅用于信息目的-类似于显示报告信息;它们不封装任何业务规则。顺便说一句,那是一个有趣的视频 - 很惊讶我以前没有遇到过它:) 谢谢,戴夫
    • 很好的答案。我面临着完全相同的问题,您的回答非常有启发性。
    • 这是一个相关的 SO 问题。 Mohamed Abed 回答中的一些链接非常有用。 stackoverflow.com/questions/7365913/…
    • 存储库从来都不是用来查询的:jefclaes.be/2014/01/repositories-where-did-we-go-wrong_26.html
    • 如果视频链接失效,here is another one
    【解决方案2】:

    我愿意:

    1. 返回一个不同的对象,它代表我的对象的视图以供显示,例如客户信息。
    2. 返回一个数据表。通用容器通常是最简单、最好的方法。

    如果您的通用基础存储库中的 T 是客户,那么我认为您误用了聚合根的概念,尽管我不是严格的 Evansangelist。我会为客户设计一个存储库,它返回任何与客户在逻辑上或舒适地分组的数据,包括作为客户数据视图的 DataTables 或只读对象。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-04-23
      • 1970-01-01
      • 1970-01-01
      • 2011-09-21
      • 2019-06-01
      • 1970-01-01
      相关资源
      最近更新 更多