4

我有以下问题。给定。CQRS + EventSourcing 应用程序。这怎么可能改变历史中聚合根的状态?

例如,会计申请,会计想申请交易但日期已过。将存储在事件存储中的事件将具有比最近事件更早的日期,但该事件的序列号会更大。

存储库将通过按序列号对事件进行排序来恢复聚合根的状态。如果我们将拍摄过去日期的快照 - 我们将拥有没有此事件的聚合根。

我们当然可以将存储库的逻辑更改为按日期对事件进行排序,但是我们使用 CQRS 的外部框架,这是不可取的。

这种情况有一些优雅的解决方案吗?

4

5 回答 5

10

您正在寻找的是双时间实现。

例如,在 12 月 3 日,我们认为 X == 12 (as-at),但在 12 月 5 日,我们纠正了错误,现在知道 X == 14 在 12 月 3 日 (as-of)

有两种方法可以实现这一点

1) 事件存储保存原始数据,投影保存原始数据(可能的变化是原始和原始投影)

2) 聚合有一个重载方法,指示对事件存储中的 as-of 与 as-at 值的需求。这很可能涉及使用自定义辅助快照流来获取当前数据值。

您的解决方案很可能同时使用这两种实现,因为一种以命令为中心,另一种以查询为中心。

当收到纠正事件时,需要重建第二个选项中聚合根的最新快照。

Martin Folwler 在本文中谈到了这一点

注意:事件存储仍然只是附加的。

于 2012-11-20T23:33:25.887 回答
6

在会计方面,如果您更改过去的预订,您可能最终会入狱。不要改变过去。请改用补偿命令。

抱歉,但您提出了会计示例,这可能是一个非常严格地摆弄过去数据而不明确更改的领域。

如果上述内容不适用于您的域,您可以轻松地在旧事件之上应用新事件,从而更改域对象的状态(可能还有历史记录)。

以预订帐户为例。该事件可能发生在今天,但它可以将实际预订日期设置为过去的某个时间。

于 2012-11-20T18:47:54.050 回答
1

对此的一种解决方案是将事件视为明确的补偿动作。例如,当您的银行撤销费用时,他们不会删除现有交易,而是添加补偿交易。该交易可以引用他们希望通过各自的约会来补偿的交易。通过这种方式,事件是现实的适当表现。

于 2012-11-20T18:52:15.290 回答
1

会计不允许你改变历史。它只允许您添加条目。您可以根据自己的意愿解释这些事件的日期,这取决于您的业务逻辑。在这种情况下,事件序列不仅仅是与事件溯源一样的持久性技巧,而是域的实际内容!

于 2012-11-20T18:41:07.840 回答
1

您已声明您的业务逻辑允许您添加回溯交易;现在我不知道你为什么想要那个,但是没有什么限制你的聚合不接受它。当然,该事件将获得稍后的事件序列号/版本,但这是意料之中的。

你不需要摆弄基础设施、存储库或其他任何东西来做到这一点。

于 2012-11-20T18:29:20.983 回答