Architecture DDD:聚合根需要来自另一个聚合根的信息

Architecture DDD:聚合根需要来自另一个聚合根的信息,architecture,domain-driven-design,aggregateroot,Architecture,Domain Driven Design,Aggregateroot,我正在考虑一个相当简单的问题的设计,但我希望听到其他解决方案来妥善处理它 在他那一刻,我有两个聚合根: 用户:保存有关用户的信息,如显示名称、链接帐户和配置文件(可以是患者配置文件或护理提供者配置文件)。此类患者档案包含出生日期和性别等信息。我有一个UserRepository,负责获取和保存用户。 筛查:保存有关健康的信息,如长度和体重测量,以及所有类型的计算信息,如基于这些长度和体重的“短期演变”。我有一个ScreeningRepository,负责获取和保存用户。 因此,在筛选中有一种计算

我正在考虑一个相当简单的问题的设计,但我希望听到其他解决方案来妥善处理它

在他那一刻,我有两个聚合根:

用户:保存有关用户的信息,如显示名称、链接帐户和配置文件(可以是患者配置文件或护理提供者配置文件)。此类患者档案包含出生日期和性别等信息。我有一个UserRepository,负责获取和保存用户。 筛查:保存有关健康的信息,如长度和体重测量,以及所有类型的计算信息,如基于这些长度和体重的“短期演变”。我有一个ScreeningRepository,负责获取和保存用户。 因此,在筛选中有一种计算方法,目标是在筛选中添加权重和/或长度时,立即重新计算健康属性,如短期进化,以便筛选始终处于一致和正确的状态

问题在于,此计算还需要用户的性别和出生日期,这些信息存储在患者档案中

因此,聚合根筛选基本上依赖于聚合根用户。所以我想知道怎么做

根据DDD,聚合根不应引用另一个聚合根。而且,如果我将用户作为筛选的属性,那么ScreeningRepository也将负责对用户进行非物质化,这当然不是他的任务

若筛选并没有参考用户,那个么Calculate并没有所有需要的信息。所以这意味着我可能应该把它转移到一个域服务,该服务将用户和筛选作为输入,并进行计算。好的但是,我如何确保在将测量添加到筛选中时,触发计算

我考虑的另一个选择是不将筛选设置为聚合根,而将其设置为与父用户的聚合。这也允许我更好地验证筛选,因为我也可以访问用户。它将解决有关计算的所有问题,因为我手头有所有信息,但这样,UserRepository将负责处理筛选,而我的聚合根将负责用户和筛选

在这一点上,最后一个选项似乎是唯一一个可以轻松解决问题的选项,但我很想听听大家的想法,因为我可能会遗漏一些明显的概念。

没有什么神奇之处

如果用于筛选的域逻辑需要性别和出生日期,则需要将这些值的副本获取到聚合中。这反过来意味着要么在中传递值,要么在中传递支持查询值的功能

通常情况下,聚合将缓存属于另一个聚合的数据的本地副本。在这种情况下,您可能需要解决缓存数据需要失效时会发生什么情况,例如:如果我们以后在出生日期发现数据输入错误时会发生什么情况?

没有什么神奇之处

如果用于筛选的域逻辑需要性别和出生日期,则需要将这些值的副本获取到聚合中。这反过来意味着要么在中传递值,要么在中传递支持查询值的功能


通常情况下,聚合将缓存属于另一个聚合的数据的本地副本。在这种情况下,您可能需要解决缓存数据需要失效时会发生什么情况,例如:如果我们以后在出生日期发现数据输入错误,会发生什么情况?

聚合是DDD中最容易被误解的概念

用户:保存有关类似用户的显示名称的信息

这与数据无关,始终与行为有关。只是一个实践建议:在第一次迭代中,将整个有界上下文作为单个聚合,所有内容都放在单个对象中

会发生什么?首先,您现在能够满足在有界上下文中可能存在的每个不变量。好吧,但你会说,这太疯狂了,我不能只在一个对象中加载所有内容,这会非常慢,在这段时间内没有其他人可以使用该对象。对的聚合的存在只有一个原因:性能优化!这取决于您找到互不影响的不变量,以便您可以分割对象以提高系统的性能。如何分割对象

似乎患者档案可能是聚合根的一个很好的候选者,方法屏幕封装了当前的筛查逻辑,并设置了WeightInkGW来修改权重。护理提供者档案可以是另一个集合。另一个帐户。所有这些都只是持有一个用户ID以供参考

目标是将属于一个集合的不变量放在一起,然后
把那些没有的分开,都是为了表现

聚合是DDD中最容易被误解的概念

用户:保存有关类似用户的显示名称的信息

这与数据无关,始终与行为有关。只是一个实践建议:在第一次迭代中,将整个有界上下文作为单个聚合,所有内容都放在单个对象中

会发生什么?首先,您现在能够满足在有界上下文中可能存在的每个不变量。好吧,但你会说,这太疯狂了,我不能只在一个对象中加载所有内容,这会非常慢,在这段时间内没有其他人可以使用该对象。对的聚合的存在只有一个原因:性能优化!这取决于您找到互不影响的不变量,以便您可以分割对象以提高系统的性能。如何分割对象

似乎患者档案可能是聚合根的一个很好的候选者,方法屏幕封装了当前的筛查逻辑,并设置了WeightInkGW来修改权重。护理提供者档案可以是另一个集合。另一个帐户。所有这些都只是持有一个用户ID以供参考


目标是将属于同一聚合的不变量放在一起,并将不属于的不变量分开,所有这些都是为了性能

谢谢你的意见!我遇到的另一个问题是,如果筛选无法引用用户,我无法完全验证筛选,例如,您可能会为没有患者档案的用户创建筛选。现在,我只是重新组织了所有内容,以便筛选现在是用户根目录的一部分,只是想尝试一下。这解决了我遇到的所有问题,但是UserRepository现在还检索/保存筛选和度量。我计划添加一个布尔IncludeScreening,以便您可以指定是否应加载筛选。我想这给了我最好的两个世界…谢谢你的意见!我遇到的另一个问题是,如果筛选无法引用用户,我无法完全验证筛选,例如,您可能会为没有患者档案的用户创建筛选。现在,我只是重新组织了所有内容,以便筛选现在是用户根目录的一部分,只是想尝试一下。这解决了我遇到的所有问题,但是UserRepository现在还检索/保存筛选和度量。我计划添加一个布尔IncludeScreening,以便您可以指定是否应加载筛选。我认为这给了我两全其美的东西……你的建议与沃恩·弗农(Vaughn Vernon)在《领域驱动设计》(Domain Driven Design)一书中给出的建议相反。在“骨料的战术设计”一章中,他谈到了如何调整骨料的尺寸,第一步是设计小骨料,第二条规则,虽然这一点更为重要,但在这个过程中,下一条规则是,你的建议与沃恩·弗农(Vaughn Vernon)在其著作《领域驱动设计》(Domain Driven Design)中给出的建议相反。在“聚合的战术设计”一章中,他讨论了如何调整聚合的大小,其中第一步是设计小聚合,第二条规则(虽然更重要,但在此过程中,第二条规则是保护聚合边界内的业务不变量)。