【发布时间】:2014-12-05 21:55:53
【问题描述】:
我正在使用 DDD/CQRS/ES 方法,我对我的聚合和查询建模有一些疑问。例如,考虑以下场景:
用户可以创建一个 WorkItem、更改其标题并将其他用户关联到它。 WorkItem 有参与者(关联用户),参与者可以将操作添加到 WorkItem。参与者可以执行操作。
假设用户已经创建,我只需要 userIds。
我有以下 WorkItem 命令:
- 创建工作项
- 更改标题
- 添加参与者
- 添加操作
- 执行操作
这些命令必须是幂等的,所以我不能添加两次相同的用户或操作。
还有以下查询:
- WorkItemDetails(工作项的所有信息)
查询由处理由 WorkItem 聚合引发的域事件的处理程序更新(在它们被持久化到 EventStore 之后)。所有这些事件都包含 WorkItemId。如果需要,我希望能够通过加载所有相关事件并按顺序处理它们来即时重建查询。这是因为我的用户通常不会访问一年前创建的 WorkItem,因此我不需要处理这些查询。因此,当我获取一个不存在的查询时,我可以重建它并将其存储在具有 TTL 的键/值存储中。
域事件有一个aggregateId(用作事件streamId和shard key)和一个sequenceId(用作事件流中的eventId)。
所以我的第一次尝试是创建一个名为 WorkItem 的大型聚合,其中包含一组参与者和一组操作。 Participant 和 Actions 是仅存在于 WorkItem 中的实体。参与者引用用户 ID,操作引用参与者 ID。他们可以获得更多信息,但这与本练习无关。使用此解决方案,我的大型 WorkItem 聚合可以确保命令是幂等的,因为我可以验证我没有添加重复的参与者或操作,如果我想重建 WorkItemDetails 查询,我只需加载/处理给定的所有事件工作项 ID。
这很好用,因为我只有一个聚合,WorkItemId 可以是聚合Id,所以当我重建查询时,我只需加载给定 WorkItemId 的所有事件。 但是,此解决方案存在大型 Aggregate 的性能问题(为什么要加载所有参与者和操作来处理 ChangeTitle 命令?)。
所以我的下一个尝试是拥有不同的聚合,所有聚合都具有相同的 WorkItemId 作为属性,但只有 WorkItem 聚合具有它作为聚合 ID。这解决了性能问题,我可以更新查询,因为所有事件都包含 WorkItemId 但现在我的问题是我无法从头开始重建它,因为我不知道其他聚合的聚合 ID,所以我无法加载他们的事件流并处理它们。他们有一个 WorkItemId 属性,但这不是他们真正的 aggregateId。我也不能保证我按顺序处理事件,因为每个聚合都有自己的事件流,但我不确定这是否是一个真正的问题。
我能想到的另一个解决方案是有一个专用的事件流来整合由多个聚合引发的所有 WorkItem 事件。因此,我可以拥有事件处理程序,将参与者和操作触发的事件简单地附加到其 id 类似于“{workItemId}:allevents”的事件流中。这将仅用于重建 WorkItemDetails 查询。这听起来像是一个 hack.. 基本上我正在创建一个没有业务操作的“聚合”。
我还有哪些其他解决方案?即时重建查询是否不常见?当使用多个聚合(多个事件流)的事件来构建相同的查询时,可以这样做吗?我已经搜索了这种情况,但没有发现任何有用的东西。我觉得我错过了一些应该非常明显的东西,但我还没想清楚是什么。
非常感谢您对此的任何帮助。
谢谢
【问题讨论】:
-
您能否进一步解释“我无法从头开始重建它,因为我不知道其他聚合的 aggregateId,因此我无法加载它们的事件流并进行处理”?是否可以在 ExcecuteActionCommand 中包含 actionId?添加操作后,可以通过 workItemId 查询来检索 actionId。还是我错过了什么?
-
是的,从头开始重建 WorkItemDetails 将加载给定 WorkItemId 的所有事件(从事件存储中)。但是 Participant 和 Action 的事件存储在它们自己的事件流中,尽管事件的有效负载可能包含 WorkItemId。这就是为什么我想为 WorkItemDetails 提供一个专用的事件流,以便在重建时我只需在该事件流中加载事件。我不想执行多个查询(可能数百个)来从多个流(聚合)加载事件。
-
对不起,我还是不明白。 WorkItemDetails 是聚合还是查询?如果是查询,是否存储为 WorkItem 的最新状态?
-
这是一个查询,根据来自多个聚合的事件更新。我的观点是,当我需要从头开始重建时,我不知道要从哪个事件流中加载,因为我需要加载,例如,来自动作 1、2 等的事件,而且我不知道有多少将有的操作及其 ID。
标签: domain-driven-design cqrs event-sourcing