Concurrency 拆分聚合根以避免并发冲突

Concurrency 拆分聚合根以避免并发冲突,concurrency,domain-driven-design,aggregateroot,Concurrency,Domain Driven Design,Aggregateroot,在准备越来越多关于聚合根的内容时,特别是来自Vaughn Vernon的I-DDD,我提出了一个关于并发性的问题 一个系统由多个用户同时访问。(当前)核心领域是关于教育中心的“注册”,因此有一个学生实体代表业务的主要客户Student是一个聚合根,当然有很多信息 假设一个学生有一个个人地址和学术信息(过去的学校、年级等),这两个都是作为聚合中的价值对象建模的,并且为了论证,在同一聚合中没有其他实体。Student聚合在实体中使用类似version属性的乐观并发,因此对其数据的任何更改都将增加该版

在准备越来越多关于聚合根的内容时,特别是来自Vaughn Vernon的I-DDD,我提出了一个关于并发性的问题

一个系统由多个用户同时访问。(当前)核心领域是关于教育中心的“注册”,因此有一个
学生
实体代表业务的主要客户
Student
是一个聚合根,当然有很多信息

假设一个
学生
有一个
个人地址
学术信息
(过去的学校、年级等),这两个都是作为聚合中的价值对象建模的,并且为了论证,在同一聚合中没有其他实体。
Student
聚合在实体中使用类似version属性的乐观并发,因此对其数据的任何更改都将增加该版本

问题是,如果两个不同的用户试图同时修改同一
学生的
个人地址
学术信息
,其中一个尝试将失败,即使地址和学术信息完全无关;虽然两者都是VO,但它们属于同一个聚合

我想我可以拆分聚合以避免并发冲突,因为除了两个“属于”同一个
学生
之外,没有与
PersonalAddress
AcademicInformation
相关的真正不变量。但这些都是没有身份的VO。我必须创建另一个实体,并将它们放在不同的聚合根中,它们都包含与同一个学生相关的信息,因此可以同时修改这些信息

因此,问题是:

  • 如何避免修改同一实体(
    Student
    )的不相关信息的并发冲突,该实体被建模为值对象(
    PersonalAddress
    AcademicInformation
  • 这是一个“好方法”™ 如前所述,将
    Student
    聚合拆分为两个或多个不同的聚合根
  • 即使这一特殊情况可以通过其他方式解决(如果我能分享这一点,我将不胜感激),如何从更广泛的角度解决这一问题
  • 我认为这一切都取决于用户尝试同时修改信息的频率,并在此基础上决定拆分聚合是否值得。。。但我不知道

    非常感谢。

    1)您可以通过其他方式使用乐观并发:基于旧值,而不是版本号。例如,更改Student的命令应类似于new ChaneStudentCmd{StudentId=…;OldAddressStreet=“xxx”;NewAddressStreet=“yyy”},在更改之前,实现应确保当前stret为“xxx”。如果不是“xxx”,则应引发并发异常

    2) 我认为没有理由分割总量


    3) 一般方法可以使用更具体的更新命令,而不是简单的“更新所有学生属性”。业务层应该有用户想要更新的信息。有了这些信息,它将能够优雅地处理更新,同时考虑到并发性和其他需求。

    在我看来,您可以保持原样,这是最简单的方法。但是,将不相关的属性或方法保留在一个聚合/实体/类中会违反“高内聚性”规则。 所以我想知道你们的处境是否是一种未被发现的有界语境的“气味”。
    个人地址
    学术信息
    是否属于同一个有界上下文?我不知道你的域名和用例,但是你应该考虑这个。

    回答您的问题:

    公元1年。通过将无关信息分离到不同的有界上下文或集合中来避免冲突。不过,在相关信息上仍然可能存在并发冲突

    公元2年。这是对有界上下文进行建模和正确聚合的“好方法”(尽管不容易)。所以并发冲突和不相关的信息是“气味”,它让您知道您在模型中遗漏了一些东西

    公元3年。同样,适当的有界上下文和聚合建模

    我并不是说在每种情况下都有办法通过分离BC和聚合来避免遇到的问题,但我确实觉得这是可能的。我并不是说,在一个聚合中并没有不相关的属性和方法总是正确的,但这正是“高内聚”规则让我想到的