29

我对 DDD 和存储库模式有疑问。

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

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

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

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

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

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

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

但是这两种感觉我都在违背 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 适合您!

4

2 回答 2

30

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

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

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

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

于 2010-01-20T00:25:05.157 回答
1

我会:

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

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

于 2010-01-20T00:23:56.657 回答