首页 文章

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

提问于
浏览
3

我正在使用DDD / CQRS / ES方法,我有一些关于建模我的聚合和查询的问题 . 作为示例,请考虑以下情形:

用户可以创建WorkItem,更改其 Headers 并将其他用户与其关联 . 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就像“:allevents” . 这仅用于重建WorkItemDetails查询 . 这听起来像一个黑客..基本上我正在创建一个没有业务操作的“聚合” .

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

对此有任何帮助非常感谢 .

谢谢

1 回答

  • 1

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

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

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

    如果您使用多个小聚合路径并且您的读取模型需要来自多个来源的信息来更新自身,您有几个选项:

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

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

    CQRS events do not contain details needed for updating read model

相关问题