我有一个关于CQRS架构上涉及多个聚合的预测的问题 .
例如,假设我有两个聚合 WorkItem
和 Developer
并且以下事件按顺序发生(但不是立即发生)
-
WorkItemCreated(workItemId)
-
WorkItemTitleChanged(workItemId,title)
-
DeveloperCreated(developerId)
-
DeveloperNameChanged(developerId,name)
-
WorkItemAssigned(workitemId,DeveloperId)
我希望创建一个投影,它是开发人员 - 工作项的“内部联接”:
| WorkItemId | DeveloperId | Title | DeveloperName | ... |
|------------|-------------|--------|---------------|-----|
| 1 | 1 | FixBug | John Doe | ... |
我正在进行预测的方式是渐进式的 . 含义我从数据库加载已保存的投影并应用剩余的事件 .
我的问题是,负责在投影表上创建一行的事件是 WorkItemAssigned
. 但是,该事件不包含先前事件所需的信息(工作项目 Headers ,开发者名称等)
为了在 WorkItemAssigned
之前获得所需信息,我必须从eventstore加载所有事件,为所有 WorkItems
和 Developers
保持内存状态,以便在 WorkItemAssigned
事件到达时获得所需信息 .
当然,我可以为 Workitem
投射,另一个投射 Developer
并查询它们以检索它们的最后状态 . 但是看起来很多工作,如果我要分别为每个聚合创建投影,我不妨创建一个数据库视图来内连接它们(事实上,这就是我正在做的事情 . )
我不是手工完成这一切,我目前正在使用一个名为EventFlow的好框架,但它并没有指示我回答这个问题 .
这是一个关于CQRS基本原理的问题,我在这里失去了一些东西 .
1 回答
我不认为你错过任何东西 . 在事件源系统中投影读取模型提出了一组不同于从关系模型查询的问题 . 问题不一定更容易或更难解决;他们只是 different .
好消息是你有很多选择 . Event Sourcing允许您以任何可想象的方式投影数据,因此您可以决定最适合每个投影的解决方案 . 我猜“坏”消息(我认为这不是坏消息)是问题的解决方案每次都与关系系统不一样,即使用JOIN构造查询 .
您已经确定了一些可能的解决方案:
使用关系模型作为读取模型之一
当某种类型的事件进入时,重新查询包含所需数据的流并使用它们按需投影
您还可以简单地在临时状态(内存,文档数据库,文件系统等)中保存一些数据,这些数据允许您在需要时查找数据并进行投影 . 因此,每当WorkItemAssigned事件进入时,请保留更新的WorkItems和Developers列表,以便读取和使用它们 .
我想说,创建一个关系数据库作为临时或永久读取模型是解决问题的一种非常可行的方法,假设您没有尝试实现大规模可伸缩性 .