事件存储根聚合与聚合

时间:2017-01-28 19:41:24

标签: aggregate cqrs event-sourcing event-store

事件存储中的“根聚合”和“聚合”之间有什么区别?

即使经过数小时的搜索,我也无法准确定义这些内容。我的理解是聚合是一个ID表,它将商店中的事件(集合)组合在一起,通常使用对象表示,这也是聚合类型的原因。

此外,我已经看到了带有版本号的聚合表,我觉得这些表很混乱,前提是它们本质上是表示事件集合的组/容器/聚合ID。

2 个答案:

答案 0 :(得分:7)

因此,我们同意您尝试将事件流设置为DDD聚合根和聚合模式。

有一种常见的模式,即每个聚合都有自己的流。它具有聚合根的名称和标识,但名称部分不是必需的。

整个聚合上的所有操作都由事件表示,然后将事件写入此流。

因此,如果您有一个聚合根MyNamespace.Order,它有多个子值对象或实体MyNamespace.OrderLine,则所有对行的操作都是通过访问聚合根方法完成的,并且所有事件都写入一个流,所以对于ID为123的订单,它将是:

Stream:MyName

  • space.Order-123
  • OrderPlaced
  • OrderDeliveryAddressSet
  • OrderLineAdded
  • OrderLineAdded
  • OrderLineRemoved
  • OrderConfirmed
  • OrderETASet
  • OrderPaid
  • OrderDispatched
  • OrderDelivered

实体的概念没有在事件存储方面表示,因为您无法轻松定义不同流之间的关系以从多个流中读取事件以重构聚合。因此,所有事件都在聚合根流中写入和读取,然后成为整个聚合的 流。

关于聚合的一个重要规则是聚合也是一致性边界。这基本上意味着聚合上的所有操作必须在一个事务中完成。

保持事件版本以处理并发非常重要。当您从事件存储中读取聚合时,您也会获得最新的事件版本。执行操作后,您将写回新事件,检查最新事件版本是否仍然相同。如果最后一个事件版本不匹配,则抛出并发异常,因为有人已经更改了聚合并在您发生冲突之前将更改写入了商店。

关于"表"我不太清楚你的意思。当然,您可以在表格中对事件存储进行建模,并且在执行此操作时有不同的策略。更常见的是,您不希望使用专门的事件存储,例如this one

答案 1 :(得分:2)

DDD书籍和术语并不专门针对事件采购(它还不是一件事)。

SE Radio podcast 226 with Eric Evans涵盖了这一点。

聚合是一组相关的实体和价值对象,聚合,模拟需要保持内部一致的单个事物(或相关的一组事物)

聚合根可以是查看聚合“通过”的根实体(例如,您拥有它的发票实体和一组单独的订单行)

令人遗憾的是(但Naming很难),人们觉得需要重复使用Aggregate一词来指代在流中执行事件聚合的事物(即使相关事件集合在一起确实代表了状态总计)。

在实施DDD书中,功能事件采购附录将IIRC分离出来 - 我倾向于将这个事物(聚合的相关事件聚合为制作目的)称为“折叠状态”(并且还将这种折叠状态的演变与实际决策分开)

预测(在DDD-CQRS-ES的说法中)指的是一系列抽象事件,它们根据新事件做出适当的事情(代表人们做出的决定)。投影可以维护非规范化视图 ala您的“摘要”(不仅有一个)。流有事件。决策过程将折叠这些事件以推断相关背景以进行决策。 投影可以具有状态(通过对与流(或其集合)相关的事件的相关子集的良好有序观察来构建) - 它可以是保持在密钥中的斑点 - 价值商店随时可以轻松查询。它可能是每个流的内存总数,您通过每次从头开始读取来构建。它可能是一个类似的内存缓存,它由某种形式的检查点支持(最后一个事件的第一个事件),以及一个将其汇总到该点的序列化形式。它可以是很多。或者在堕落的情况下,你可能还没有找到任何东西。