我正在考虑一个相当简单的问题的设计,但是我想听听其他解决方案来正确处理它。
目前他有2个聚合根:
User
:保存与display name
,linked accounts
和profile
之类的用户有关的信息,该用户可以是patient profile
或{{1} }。这样的患者资料包含care provider profile
和birth date
之类的信息。我有一个gender
,负责获取和保存用户。UserRepository
:根据这些长度和权重保存有关健康的信息(例如长度和体重测量值)以及各种计算出的信息(例如“短期演变”)。我有一个Screening
负责获取和保存用户。因此ScreeningRepository
中有一个Calculate()
方法,目标是将Screening
和/或weight
添加到length
时,系统会立即重新计算screening
之类的运行状况属性,以使short term evolution
始终处于一致且正确的状态。
问题在于该计算还需要用户screening
和gender
,这些用户存储在birth date
中。
因此,基本上,聚合根patient profile
依赖于聚合根screening
。所以我想知道如何去做...
根据DDD,聚合根不应引用另一个聚合根。而且,如果我将user
设为user
的属性,那么screening
也将负责使用户非物质化,这当然不是他的任务。
如果ScreeningRepository
没有对screening
的引用,则user
没有所有需要的信息。因此,这意味着我可能应该将其移至域服务,该域服务将Calculate()
和user
作为输入并进行计算。精细。但是,如何确定将测量添加到筛选后,screening
会被触发?
我正在考虑的另一种选择是不使Calculate
成为聚合根,而使其仅与父级screening
聚合。这也使我可以更好地验证user
,因为我也可以访问screening
。它将解决有关计算的所有问题,因为我手头将拥有所有信息,但是通过这种方式,User
将同时负责处理UserRepository
,并且我的聚合根将成为{{1 }}和screening
。
在这一点上,最后一个选项似乎是唯一可以轻松解决问题的选项,但是我很想听听关于事情的任何想法,因为我可能会缺少明显的概念。
答案 0 :(得分:1)
没有魔术。
如果Screening
的域逻辑要求性别和生日,那么您需要将这些值的副本复制到汇总中。反过来,这意味着(a)传入值,或(b)传入支持查询值的功能。
通常情况是一个聚合将缓存一个“属于”另一个聚合的本地数据副本。在这种情况下,您可能需要研究如果需要使缓存的数据无效的情况(例如:如果我们以后在生日时发现数据输入错误会发生什么情况?)
答案 1 :(得分:1)
聚集是DDD中最容易被误解的概念。
用户:保存有关用户的信息,例如显示名称
它永远与数据无关,而始终与行为有关。只是一个实践建议:在第一次迭代中,将整个有界上下文变成单个聚合,所有内容都放在单个对象中。
会发生什么?首先,您现在可以满足有界上下文中可能存在的每个不变式。好的,但是您会说这很疯狂,我不能只将所有内容加载到单个对象中,这将非常慢,并且在此期间没有其他人可以使用该对象。正确!聚合仅存在于一个原因:性能优化!由您决定永不影响彼此的不变式,以便您可以拆分对象以提高系统性能。如何分割对象?
似乎,通过使用封装了当前Screening逻辑和SetWeightInKg(w)来修改体重的Screen()方法,患者概况可能是聚集根的良好候选者。护理人员资料可能是另一个汇总。帐户另一个。所有人都只是持有一个UserId供参考。
目标是将属于在一起的不变式放在单个集合中,将不存在的不变式分开,这都是为了提高性能。