我在使用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 …Run Code Online (Sandbox Code Playgroud) 在同步环境中,很容易创建一个范围上下文,允许您将带外上下文附加到当前线程.例如,当前的TransactionScope或线程静态日志记录上下文.
using (new MyContext(5))
Assert.Equal(5, MyContext.Current);
Assert.Equal(null, MyContext.Current);
Run Code Online (Sandbox Code Playgroud)
使用IDisposable和线程静态字段的组合可以轻松实现上下文.
显然,当使用异步方法时,这会分崩离析,因为上下文基于线程静态字段.所以,这失败了:
using (new MyContext(5))
{
Assert.Equal(5, MyContext.Current);
await DoSomethingAsync();
Assert.Equal(5, MyContext.Current);
}
Run Code Online (Sandbox Code Playgroud)
当然我们也希望将上下文传递给调用链中的异步方法,所以这也应该有效:
using (new MyContext(5))
{
Assert.Equal(5, MyContext.Current);
await AssertContextIs(5);
}
Run Code Online (Sandbox Code Playgroud)
有没有人知道如何实现这一点?使用async/await模式时丢失带外上下文会使代码的某些部分变得非常难看.
考虑异步WebAPI调用,您希望将基于请求的上下文用于日志记录.您希望调度堆栈深处的记录器能够知道请求ID,而无需使用参数将整个请求ID一直传递到调用堆栈.
谢谢你的帮助!