Domain driven design 聚合是否可以是域事件的一部分?

Domain driven design 聚合是否可以是域事件的一部分?,domain-driven-design,cqrs,aggregateroot,domain-events,Domain Driven Design,Cqrs,Aggregateroot,Domain Events,考虑具有许多属性的聚合。例如UserGroup。如果我想发布UserGroupCreatedEvent,我可以做两件事: 将刚创建的用户组中的属性复制到 UserGroupCreatedEvent并复制其值。或: 请参阅UserGroupCreatedEvent中的新用户组 在许多例子中,比如Axon的Contacts应用程序,我看到了属性重复。我想知道为什么,如果在现实世界的CQRS应用程序中,这不是很大的开销,开发人员会选择引用聚合。域事件的一个重要属性是它们是不可变的。考虑到这一点,您提到

考虑具有许多属性的聚合。例如UserGroup。如果我想发布UserGroupCreatedEvent,我可以做两件事:

  • 将刚创建的用户组中的属性复制到 UserGroupCreatedEvent并复制其值。或:

  • 请参阅UserGroupCreatedEvent中的新用户组


  • 在许多例子中,比如Axon的Contacts应用程序,我看到了属性重复。我想知道为什么,如果在现实世界的CQRS应用程序中,这不是很大的开销,开发人员会选择引用聚合。

    域事件的一个重要属性是它们是不可变的。考虑到这一点,您提到的两种可能性大相径庭:

    • 复制属性记录创建
      UserGroup
      时属性的值
    • 通过ID引用
      UserGroup
      只会告诉您创建了
      UserGroup
      ,而不是它当时拥有的属性。如果同时删除了
      用户组
      ,则表示信息丢失
    复制哪些属性取决于这种差异。您是否需要能够在创建时查找
    用户组
    的名称?将其添加为属性。如果没有(如果不期望它会被要求),就不要这样做

    此外,域事件有一个全局范围(即,它们在BC之外是有意义的),因此您应该包括BC之外的客户端了解域事件所需的所有信息


    请注意,将整个聚合根对象附加到域事件违反了域事件的不变性规则,因此这很可能是个坏主意。

    事件是DTO,它意味着跨越边界。直接包含骨料存在以下问题:

    • 聚合是一个仅在其自身有界上下文中才有意义的概念
    • 一个事件应该只包含相关的变化,而不是概念的整个状态
    • 因为事件是DTO,所以在某一点上它将被(反)序列化,这对于正确封装的对象来说是一个技术问题
    • 接收处理事件的每个组件/上下文都与定义聚合的组件有依赖关系
    这就是为什么域事件应该只是相关状态更改的扁平表示的主要原因


    注:如果您需要在事件中包含整个状态,可能事件设计不当,或者您正在处理一个简单的数据结构。通常,聚合包含一些值对象和/或封装一些业务约束。

    感谢这一伟大的见解,再加上MikeSW的回答,将事件视为消费者处理事件所需的最小数据集是完全有意义的。在用户组的创建时,它有一个名称、描述、日期,隐私设置,创建者用户(所有者)。我认为GroupStartedEvent应该包含所有这些数据,以便重现用户组的状态(即在事件重播的情况下),不是吗?@Pepster:是的,如果创建者不是实体。要使事件不可变,其所有成员也必须不可变。因此,如果创建者是一个实体,那么您可能应该将创建者ID放在事件中,而不是整个用户。