5

我有一个关于使用JOliver 的 Event Store在单个事务中更新多个聚合的问题。据我了解,每个聚合都应该有自己的事件流。现在,虽然许多命令处理程序只会加载单个聚合并只更新该聚合(即为这些聚合保存事件),但我可以想象会有需要更新多个聚合的命令处理程序。当然,我想以交易的方式做到这一点。

但是,我不知道如何使用 Event Store 做到这一点。通过调用CommitChanges()事件流来存储事件。如果我们有多个要更新的聚合,将有多个事件流,因此会多次调用CommitChanges(). 使该事务具有事务性的唯一方法是将其包装在 中TransactionScope,但这没有多大意义,因为底层存储技术可能不支持事务。所以我最终得到了这段代码,这绝对不是我想要的:

        Guid aggregateGuid1 = Guid.NewGuid();
        Guid aggregateGuid2 = Guid.NewGuid();
        Guid commitGuid = Guid.NewGuid();

        var stream = store.OpenStream(aggregateGuid1, 0, int.MaxValue);
        stream.Add(new EventMessage() { Body = new MonitorDisabled { MonitorGuid = aggregateGuid1, User = "A" } });
        stream.CommitChanges(commitGuid);

        stream = store.OpenStream(aggregateGuid2, 0, int.MaxValue);
        stream.Add(new EventMessage() { Body = new MonitorEnabled { MonitorGuid = aggregateGuid2, User = "B" } });
        // Can't commit twice with the same commit id, what if fails after first one? No way for the store to know it had to write the second part of the commit.
        stream.CommitChanges(commitGuid);

这让我觉得我完全错过了应该如何使用 Event Store 的一些东西。有人可以帮我吗?非常感谢!

4

3 回答 3

8

聚合定义事务边界。

如果您需要执行跨聚合交易,您应该检查您的聚合并可能重新设计它们。

如果一个操作(命令)影响多个聚合,并且您确信您的聚合设计良好并且映射到您的域中的真实一致性边界,那么最终一致性可能就是您正在寻找的。只需向每个聚合发送一个命令,并有两个事务,每个事务一个。如果你觉得最终的一致性不适合你的情况,恐怕它又回到了绘图板上。

于 2011-11-16T13:21:32.113 回答
3

我不能代表 John Oliver,但我认为答案是“不要”。聚合是事务边界。如果您需要协调多个聚合的提交,则需要一个显式的协调过程,例如 saga,这将完成并在必要时撤消相关事件。

于 2011-11-16T13:03:42.717 回答
0

有时,如果您的基础架构支持分布式事务,则在这些场景中利用分布式事务会更容易。

带有 EventStore 的 TransactionScope:

默认情况下,EventStore 在将更改提交到数据库之前会抑制 NServiceBus 创建的任何环境事务。但是,如果您使用支持分布式事务(MSMQ、SQL Server、Raven 等)的队列和数据库,则可以将 EventStore 的 TransactionScopeOption 更改为必需。这将确保 EventStore 在环境事务中登记,其中将使用 MSDTC 进行分发,并且消息队列和数据库将保持同步。- NES 文档

使用 RavenDB 的跨文档事务:

你会从我死去的、冰冷的、断了的手上撬开交易 - Ayende

于 2011-11-29T16:50:41.010 回答