事件溯源中每个事件流有多个聚合

More than one Aggregate per Event Stream in Event Sourcing

假设一个事件流是一个事务边界,聚合是一个写入模型来强制执行不变量,我可以有两个或更多聚合专用于一个事件流吗?如果由于性能或过于复杂的设计原因不能选择一个大聚合体?

例如,我有以下由一个事件流表示的域模型:

{
  "Products": [{
      "Id": 1,
      "Name": "Call-Centre",
      "Services": [
          {
              "Id": 10,
              "Name": "CloudStorage",
              "Price": 250,
              "Discount": 100
          }
      ]
}]

我需要执行两个不变量。第一:每个产品的服务必须是唯一的(按名称)。第二:服务折扣值不能超过实际价格。 现在我考虑使用两个聚合: ProductAggregate 包含用于执行第一个不变量的服务集合; ServiceAggregate 仅包含用于执行第二个的服务信息。 我的解决方案是否存在缺陷?

一般来说,您不能将聚合嵌套在其他聚合中。他们可以通过根引用另一个聚合。您可以使对给定聚合的所有访问都通过另一个聚合。

例如产品汇总可能是这样的:

{
  "Id": 1,
  "Name": "Call-Centre",
  "Services": {
    "CloudStorage": 10
  }
}

服务聚合可能是:

{
  "Id": 10,
  "Name": "CloudStorage",
  "Price": 250,
  "Discount": 100
}

如果服务实际上是产品的子项(产品 1 的 CloudStorage 不同于产品 2 的 CloudStorage),那么您可以通过在服务(并且很可能有一个域约束,一旦服务与产品相关联,服务中的 Product 字段就不能更改)。涉及关系的操作可能会变成 sagas(例如,向产品添加服务或更新服务名称)。也可能值得将该关系编码到服务 ID 中,但如果 ID 可以是字符串或其他内容,这可能会更容易。

因为它们是不同的聚合,所以它们在概念上是不同的事件流(因为聚合定义的事务边界至少与事件流一样多)。将 2 个事件流投影为一个可能很有用:该投影可能能够正确排序两个源流之间的事件。这种排序的逻辑将取决于域(例如,知道哪些操作可以交错,哪些可以假设不是(例如,因为它们由 saga 协调))。