首先,我对聚合的理解/假设。 *聚合是唯一可以直接访问的域对象。如果聚合中有子级,则必须通过聚合来访问它们。 *聚合可以通过其ID引用其他聚合。这意味着我可以通过其存储库加载聚合A,通过该存储库获得对聚合B和加载B的ID引用。 *如果同时单独更新根聚合和子实体,则大型聚合可能会导致并发问题。
例如,我有一个基于章节的会员制。各章都有成员。用户应该能够同时对不同的成员进行更改,从而使我能够将Chapter和Member各自设置为自己的集合。
但是我们有一条规则说
我觉得我应该有这样的代码
var member = chapter.EnrollMember(memberInfo);
如果该章已具有与为B传递的参数匹配的成员,则该代码应该引发错误。但是,如果该章聚合中仅具有对其他成员的ID引用,那么应该如何获取这些成员?
注意:这是一种假设情况。我正在寻找这种情况如何建模,而不是是否应该以这种方式建模。
答案 0 :(得分:1)
在大范围内对大型集合进行集合验证通常是不实际的。如果使用关系数据库,则可以使用唯一约束来保护该不变式。
另一种方法可能是依靠最终的一致性,在这种情况下,您可以在规则破损后检测出规则破损并发出补偿措施(自动或手动)。为了确定是否可以选择最终一致性,您必须评估为企业打破这一规则的成本,这就是为什么对假设情景进行建模没有那么大的帮助。在现实世界中,您会问为什么为什么会员不能拥有相同的姓名和出生日期(在现实世界中完全可能)如此重要?如果违反该规则,企业将为此付出多少费用?如果在发送命令之前先在UI上对其进行了验证(例如,UI上的唯一性检查)等,那么发生的可能性有多大。
如果从某种意义上说,成员唯一性策略非常重要,必须非常一致,但是过于复杂而无法建模为唯一约束,那么您可以对仅维护最小状态以保护不变性的AR进行建模,而所有其他成员细节在单独的AR上处理。例如,成员的name
,birthdate
和status
可以在ChapterMember
内的Chapter
实体上建模,而ChapterMemberProfile
AR可以保留其他不需要设置验证的详细信息。
//Enroll
var memberProfile = chapter.enrollMember(name, birthdate, avatarFilePath);
transaction {
save(memberProfile);
save(chapter);
}
//Change avatar for a given chapter
var memberProfile = find(chapterId, name, birthdate);
memberProfile.changeAvatar(avatarFilePath);
save(memberProfile);
//Disenroll (you could also modify memberProfile in the same transaction for this specific use case -- if needed)
chapter.disenrollMember(name, birthdate);
save(chapter);