I'm having a question regarding updates to multiple aggregates in a single transaction using JOliver's Event Store. As I understand, every aggregate should have its own event stream. Now, while many command handlers will only load a single aggregate and only update that aggregate (i.e. save events for those aggregates), I can imagine that there will be command handlers which need to update multiple aggregates. And of course, I would like to do that in a transactional way.
However, I don't see how I could do that with the Event Store. Storing events is done by calling CommitChanges()
on an event stream. If we're having multiple aggregates to update, will have multiple event streams and thus multiple calls to CommitChanges()
. The only way to make that transactional is to wrap it in a TransactionScope
, but that does not make much sense, since the underlying storage technology might not support transactions. So I end up with this code, which is definitely not what I am looking for:
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);
This makes me feel I'm completely missing something on how the Event Store should be used. Could anybody help me out here? Thanks a lot!
An Aggregate defines a transaction boundary.
If you need to perform cross-aggregate transactions you should review your aggregates and maybe redesign them.
In cases where an operation ( command ) affects more than one aggregate, and you are sure that your aggregates are well design and map to real consistency boundaries in your domain, eventual consitency might be what you are looking for. Just send a command to each aggregate, and have two transactions , one for each of them. If you don't feel eventual consistency is right for your case than i'm afraid it's back to the drawing board.
I can't speak for John Oliver, but I think the answer is "don't". Aggregates are transaction boundaries. If you need to coordinate the commit of several aggregates, you need an explicit coordination process, like a saga, that will do and if necessary undo the relevant events.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With