越来越多地了解聚合根,特别是来自 Vaughn Vernon 的 I-DDD,我提出了一个关于并发的问题。
一个系统同时被多个用户访问。 (当前)核心域 是关于教育中心的“注册”,因此有一个代表业务主要客户的 Student
实体。 Student
是一个聚合根,当然有很多信息。
假设一个 Student
有一个 PersonalAddress
和 AcademicInformation
(过去的学校,成绩,...)都建模为 Value Aggregate 中的对象,并且 - 为了争论 - 在同一个 Aggregate 中没有其他 Entity。 Student
Aggregate 在 Entity 中使用类似版本属性的乐观并发,因此对其数据的任何更改都会增加该版本。
问题是,如果两个不同的用户试图同时修改同一 Student
的 PersonalAddress
和 AcademicInformation
,其中之一即使地址和学术信息完全无关,这些尝试也会失败;虽然两者都是VO,但它们属于同一个聚合。
我想我可以拆分 Aggregate 以避免并发冲突,因为除了“属于”之外,没有与 PersonalAddress
和 AcademicInformation
"给同一个 Student
。但那些是 VO 没有自己的身份。我将不得不创建另一个实体并将它们放在不同的聚合根中,它们都包含与同一学生相关的信息片段,因此可以同时修改它们。
所以问题是:
- 如何避免修改被建模为值对象(
PersonalAddress
,AcademicInformation
)? - 如我之前解释的那样,将
Student
Aggregate 拆分为两个或更多不同的Aggregate Roots 是一种“好方法”™吗? - 即使这种特殊情况可以通过其他方式解决(如果分享的话,我将不胜感激),如何从更普遍的角度解决这个问题?
我认为一切都取决于用户尝试并发修改信息的频率,并据此决定拆分聚合是否值得...但我不知道。
非常感谢。
最佳答案
1) 您可以通过其他方式使用乐观并发:基于旧值,而不是版本号。例如。改变学生的命令应该看起来像 new ChaneStudentCmd { StudentId = ...; OldAddressStreet = "xxx"; NewAddressStreet = "yyy"},实现应该确保当前的 strret 在改变它之前是“xxx”。如果不是“xxx”应该抛出并发异常。
2)我认为没有理由拆分聚合。
3) 一般方法可以使用更具体的更新命令,而不是简单的“更新所有学生属性”。业务层应该有关于那个确切的用户想要更新的信息。有了这些信息,考虑到并发性和其他需求,它将能够优雅地处理更新。
关于concurrency - 拆分聚合根以避免并发冲突,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47723264/