引言来自DDD: Tackling Complexity in the Heart of Software(第150页)
a)
对VALUE的全局搜索访问通常是有意义的,因为找到了 VALUE的属性相当于创建一个新实例 有这些属性。也有例外。例如,当我 计划在线旅行,我有时会保存一些预期的行程 然后返回选择一个预订。这些行程是价值 (如果有两个由相同的航班组成,我不在乎哪个 是谁,但他们已经与我的用户名和 完整地找回了我。
我不理解作者的推理为什么更全面地使Itinierary
值对象全局可访问而不是客户端必须全局搜索Customer root entity
然后从它遍历到此{ {1}}对象?
b)
持久对象的子集必须通过a进行全局访问 基于对象属性进行搜索......它们通常是ENTITIES, 有时具有复杂内部结构的价值对象......
为什么具有复杂内部结构的对象更常见于全局可访问而不是更简单的值对象?
c)无论如何,是否有一些关于如何确定特定值对象是否应该全局可访问的一般指导原则?
更新
a)
没有域名理由让行程可以通过 客户实体。如果不需要,为什么要加载客户实体 对于任何行为?查询通常最好不用处理 使行为领域复杂化。
我可能错了,但是当用户(即客户根实体)登录时,域模型检索用户的Itinierary
并不常见?
如果用户可以选择预订航班,那么他们通常会不时检查Customer Aggregate
(虽然英语不是我的第一语言,所以Itineraries
这个词实际上可能意味着有点不同于我认为它意味着他们选择或预订的东西。
由于已经从数据库中检索了Itinerary
,因此当Customer Aggregate
与Itinerary
一起检索时,为什么会发出Customer Aggregate
的另一个全局搜索(可能会在数据库中搜索它) ?
c)
规则很简单IMO - 如果有需要的话。它没有 取决于VO本身的结构,但取决于是否是一个实例 用例需要特定的VO。
但是这个VO实例必须与某个实体相关(即Itinerary
与特定的Customer
相关),否则正如作者指出的那样,我们可以通过其属性搜索VO,而不是只需使用这些属性创建一个新的VO实例?
第二次更新:
a)来自link:
表达关系的另一种方法是使用存储库。
当通过 repository 表达关系时,您是否实现了SalesOrder.LineItems
属性(我怀疑,因为您建议不要直接调用存储库的实体),而这些属性又会调用存储库,还是实现SalesOrder.MyLineItems(IOrderRepository repo)
之类的东西?如果是后者,那么我假设不需要SalesOrder.LineItems
属性?
b)中
要记住的重要一点是聚合并不是意味着 用于显示数据。
确实,域模型并不关心上层将对数据做什么,但如果不在应用程序和 UI 之间使用DTO层,然后我假设 UI 将从聚合中提取数据(假设我们发送到UI整个聚合而不仅仅是驻留在其中的某个实体)?< / p>
谢谢
答案 0 :(得分:1)
a)没有域名理由可以通过客户实体遍历行程。如果任何行为不需要,为什么要加载客户实体?通常最好处理查询而不会使行为域复杂化。
b)我认为他的推理是复杂的值对象是您想要查询的对象,因为您无法轻松地重新创建它们。可以使用read-model pattern解决此问题和所有与查询相关的问题。
c)规则很简单IMO - 如果有需要的话。它不依赖于VO本身的结构,而是取决于用例是否需要特定VO的实例。
<强>更新强>
a)客户聚合不太可能引用客户的行程。原因是我没有看到行程如何与客户聚合中存在的行为相关联。如果只需要显示一些数据,则根本不需要加载客户聚合。但是,如果您确实加载了聚合并且它确实包含您需要的参考数据,您也可以显示它。需要记住的重要一点是,聚合并不意味着用于显示数据。
c)客户和行程之间的关系可以用共享ID表示 - 每个行程都有一个customerId。这将允许根据需要进行查找。但是,仅仅因为这两件事情是相关的,并不意味着您需要遍历客户以获取相关实体或价值对象以供查看。更一般地,关联可以实现为direct references or via repository search。无论如何都有权衡。
更新2
a)如果使用存储库实现,则没有LineItems
属性 - 没有直接引用。相反,要获取行项目列表,请调用存储库。
b)或者您可以创建一个类似DTO的对象,一个读取模型,它将直接从存储库返回。存储库可以依次执行简单的SQL查询以获取所有必需的数据。这允许您获取不属于聚合但相关的数据。如果聚合确实具有视图所需的所有数据,则使用该聚合。但是,只要您需要更多与聚合无关的数据,请切换到读取模型。