I'm new to CQRS and need advice on the following situation in my design. A command updates state of an aggregate A; the read model needs to be consequently updated with a result of a cross-aggregate calculation method; this method belongs to another aggregate B which holds a reference to the aggregate A; the method is a function of states of both aggregate B and the referenced aggregate A. Where is the correct place for this function to be called?
My considerations (can be skipped):
- Command handler updating state of aggregate A could technically fetch aggregate B from the repository, call calculation on it and put result in the domain event; however I believe it's not command handler's job to fetch aggregates other than one being modified, even for reading purposes; also it's not command handler's job to perform calculations just to send with events rather than modify the state of domain.
- The domain event ('Aggregate A updated') raised by the aggregate A contains only updated state of aggregate A, there's not enough info on state of aggregate B. Read model's event handler has no access to domain model, so it can neither fetch aggregate B nor call the desired function on aggregate B to update read model.
- I know that any state needed by command which is external to the aggregate being modified must be passed along with the command. This way the application service, before sending the command, could fetch state of aggregate B (from read model), and put it in the command. For that I would have to move the function from aggregate B to some service and pass there states of both A and B. That would make aggregate B more anemic. Plus the above mentioned problem with doing calculations within command handler.
- I've read people suggesting that any calculations that only read model is interested in belong to the read model itself. So the read model's handler of my event would just have at its disposal all needed state and behavior to perform calculations. However that would mean I have to duplicate much of the domain model concepts at the query side; it would be too complex to have a full-blown read model.
I've just thought of the following solution: within the domain, create a handler of the domain event 'Aggregate A updated'. It would fetch aggregate B, call the calculation method on it, then raise an 'Aggregate B function result changed' event with the new calculation result in it. Then the read model is able to take the result from this event and update itself. Would this be ok?
Note just in case that I'm not using Event Sourcing.
Any thoughts on this situation would be much appreciated. Thanks!
UPDATE: making the situation more concrete
My aggregates are Worker
s (Aggregate B) and Group
s of workers (Aggregate B). Workers and Groups are a many-to-many relationship. Imagine both a Group and a Worker have some Value
property. Worker's calculateValue()
is a function of the Worker's Value plus Values of all Groups the Worker participates in. The Command described above is modifying Value
for some Group. As a result, all Workers participating in the group would return different result of calculateValue()
.
What do I want from the read model? I want a list of Workers with calculated Values (that already account for Values from the Worker's all groups). I don't even need Group at the read side. If I go the 'do calculation on the read side' way, I need Groups as well as the whole structure of relationships there. I'm afraid it would be an unjustified complication.