通过多个聚合重建来自域事件的查询

时间:2014-12-05 21:55:53

标签: domain-driven-design cqrs event-sourcing

我使用DDD / CQRS / ES方法,我对建立我的聚合和查询有一些疑问。作为示例,请考虑以下情形:

用户可以创建WorkItem,更改其标题并将其他用户与其关联。 WorkItem具有参与者(关联用户),参与者可以向WorkItem添加动作。参与者可以执行操作。

我们假设用户已经创建,我只需要userIds。

我有以下WorkItem命令:

  • CreateWorkItem
  • ChangeTitle
  • AddParticipant
  • AddAction
  • ExecuteAction

这些命令必须是幂等的,所以我不能添加两次相同的用户或操作。

以下查询:

  • WorkItemDetails(工作项的所有信息)

查询由处理由WorkItem聚合引发的域事件的处理程序更新(在它们被保留在EventStore中之后)。所有这些事件都包含WorkItemId。如果需要,我希望能够通过加载所有相关事件并按顺序处理它们来动态重建查询。这是因为我的用户通常无法访问一年前创建的WorkItems,因此我不需要处理这些查询。因此,当我获取一个不存在的查询时,我可以重建它并将其存储在带有TTL的键/值存储区中。

域事件有一个aggregateId(用作事件streamId和shard键)和一个sequenceId(用作事件流中的eventId)。

所以我的第一次尝试是创建一个名为WorkItem的大型Aggregate,其中包含一组参与者和一组操作。参与者和操作是仅存在于WorkItem中的实体。参与者引用userId,动作引用participantId。他们可以获得更多信息,但这与此练习无关。使用此解决方案,我的大型WorkItem聚合可以确保命令是幂等的,因为我可以验证我不会添加重复的参与者或操作,如果我想重建WorkItemDetails查询,我只需加载/处理所有事件给定的WorkItemId。

这很好用,因为我只有一个聚合,WorkItemId可以是aggregateId,所以当我重建查询时,我只加载给定WorkItemId的所有事件。 但是,此解决方案存在大型聚合的性能问题(为什么要加载所有参与者和操作来处理ChangeTitle命令?)。

所以我的下一次尝试是使用不同的聚合,所有聚合都具有与属性相同的WorkItemId,但只有WorkItem聚合将其作为aggregateId。这解决了性能问题,我可以更新查询,因为所有事件都包含WorkItemId但现在我的问题是我无法从头重建它,因为我不知道其他聚合的aggregateIds,所以我无法加载他们的事件流并处理它们。他们有一个WorkItemId属性,但这不是他们真正的aggregateId。此外,我无法保证我按顺序处理事件,因为每个聚合都有自己的事件流,但我不确定这是否是一个真正的问题。

我能想到的另一个解决方案是拥有一个专用的事件流来整合多个聚合所引发的所有WorkItem事件。所以我可以让事件处理程序简单地将参与者和动作触发的事件附加到一个事件流,其id的类似于" {workItemId}:allevents"。这仅用于重建WorkItemDetails查询。这听起来像是一个黑客......基本上我是在创造一个"聚合"没有业务运营。

我还有其他解决方案吗?动态重建查询是不常见的吗?当多个聚合(多个事件流)的事件用于构建相同的查询时,是否可以完成?我已经搜索了这个场景,并没有找到任何有用的东西。我觉得我错过了一些非常明显的东西,但我还没有想到什么。

对此非常感谢。

由于

1 个答案:

答案 0 :(得分:1)

我不认为您应该考虑查询问题来设计您的聚合。 Read方面就是为了这个。

在域方面,关注一致性问题(聚合有多小,域在单个事务中仍然保持一致),并发性(它可以有多大并且不会遇到并发访问问题/竞争条件?)和性能(我们会在内存中加载数千个对象来执行一个简单的命令吗? - 正是你所要求的)。

我没有看到按需阅读模型有什么问题。除了在需要时重新创建流时,它与从实时流中读取基本相同。然而,这可能是相当多的工作,因为没有非凡的收益,因为大多数时候,实体在被修改之后被查询。如果按需成为"基本上每次实体更改",您也可以订阅实时更改。至于" old"观点," old"的定义是因为它们不再被修改,所以无论是否有按需或连续系统,它们都不需要重新计算。

如果您使用多个小聚合路线并且您的阅读模型需要来自多个来源的信息进行更新,您有几个选择:

  • 使用其他数据增加发出的事件

  • 从多个事件流中读取并合并其数据以构建读取模型。这里没有魔力,Read方面需要知道特定投影中涉及哪些聚合。如果您知道它们是最新的,您也可以查询其他阅读模型,并且只为您提供所需的数据。

请参阅CQRS events do not contain details needed for updating read model

相关问题