CQRS(事件源):具有多个聚合的投影

CQRS (event sourcing): Projections with multiple aggregates

我有一个关于 CQRS 架构上涉及多个聚合的投影的问题。

例如,假设我有两个聚合 WorkItemDeveloper 并且以下事件按顺序发生(但不是立即发生)

  1. WorkItemCreated (workItemId)
  2. WorkItemTitleChanged(workItemId,标题)
  3. DeveloperCreated (developerId)
  4. DeveloperNameChanged (developerId, 姓名)
  5. WorkItemAssigned (workitemId, DeveloperId)

我希望创建一个像 "inner join" 或 developer-workitem 的投影:

| WorkItemId | DeveloperId | Title  | DeveloperName | ... |
|------------|-------------|--------|---------------|-----|
| 1          | 1           | FixBug | John Doe      | ... |

我做预测的方式是渐进的。这意味着我从数据库中加载保存的预测并应用剩余的事件。

我的问题是,负责在投影 table 上创建一行的事件是 WorkItemAssigned。但是,该事件不包含以前事件所需的信息(工作项标题、开发人员姓名等)

为了在 WorkItemAssigned 之前获得所需的信息,我必须从 eventstore 加载 all 个事件,保持 states in-memory 对于所有 WorkItemsDevelopers 所以我在 WorkItemAssigned 事件到达时获得了所需的信息。

当然,我可以为 Workitem 投影,另一个为 Developer 投影,并查询它们以检索它们的最后状态。但这似乎需要很多工作,如果我要分别为每个聚合创建投影,我还不如创建一个数据库视图来 inner-join 它们(实际上,这就是我正在做的。)

我不是手工完成所有这些工作,我目前正在使用一个名为 EventFlow 的好框架,但它并没有指导我回答这个问题。

这是一个关于 CQRS 基础知识的问题,我发现我在这里遗漏了一些东西。

我认为您没有遗漏任何东西。与从关系模型查询相比,在事件源系统中投影读取模型提出了一组不同的问题。这些问题不一定更容易或更难解决;它们只是不同

好消息是你有很多选择。事件溯源允许您以任何可以想象的方式投影数据,因此您可以决定最适合每个单独投影的解决方案。我猜 "bad" 消息(我认为这不是坏消息)是问题的解决方案每次都与关系系统不同,关系系统是使用 JOIN 构造查询。

您已经确定了一些可能的解决方案:

  • 使用关系模型作为您的阅读模型之一
  • 当某种类型的事件到来时,重新查询保存您需要的数据的流,并使用它们进行按需投影

您还可以简单地将一些数据保存在临时状态(内存、文档数据库、文件系统等),这样您就可以查找数据并在需要时进行投影。因此,请保留更新的 WorkItems 和 Developers 列表,只要 WorkItemAssigned 事件出现,就可以在其中读取和使用它们。

我认为创建关系数据库作为临时或永久读取模型是解决问题的完全可行的方法,前提是您不打算实现大规模可伸缩性。