Command and Events question.

I have a scenario where I have a DealAggregate which contains an aggregate member Tasks.
The API sends a CreateDealCommand that leads to an DealCreatedEvent which creates the deal events (with no tasks).
When a request to add task to the deal, the API sends a CreateDealTaskCommand that is handled by a CommandHandler class. The DealAggregate is loaded and a createTask method is called on the aggregate that applies the DealTaskCreatedEvent.

When a request to edit a task on the deal, the API sends a UpdateDealTaskCommand that is handled the same CommandHandler class. The DealAggregate is loaded and an updateTask method is called on the aggregate that applies the UpdatedTaskCreatedEvent.

A deal could have dozens of tasks. (Task does not have it’s own aggregate)

On the ui side I need to show the history log of what happened to the deal (which includes showing when tasks where added and/or updated). I load the EventStream for the deal and loop through the events to prepare a history log that is sent back to in the payload of the response to the ui.

So far, so good.

I also need on the ui side to show the history log of a particular task on a particular deal. Since a deal can have multiple tasks, I don’t really want to load the entire Deal EventStream to then pro-grammatically find the events for the one task I am interested on.
I am thinking I could apply the same Task events I apply on the DealAggregate on a TaskAggregate. So, I end up with the Deal EventStream I already had, but also with an EventStream for each Task that I can use when I need to show the Task history log on the ui.

Any red flags so far?

The implementation details for the TaskAggregate events is what I am more concerned about. I have 2 options in mind:

  1. On the CommandHandler class, when handling the CreateDealTaskCommand, the DealAggregate is loaded and the createTask method is called on the deal aggregate to apply the DealTaskCreatedEvent. Within the same @CommandHandler method, after calling createTask, create an instance of the TaskAggregate, and the constructor of the task aggregate would apply the DealTaskCreatedEvent on this aggregate. This would mean that the CreateDealTaskCommand would result in 2 events being applies. This is a pattern that I haven’t seen in any of the Axon examples and I’m not even sure it would work…

  2. On the CommandHandler class, when handling the CreateDealTaskCommand, the DealAggregate is loaded and the createTask method is called on the deal aggregate to apply the DealTaskCreatedEvent. A DealSaga (or Task Saga, not sure which name is more applicable) would then handle the event and send a CreateTaskCommand that would be handled by the TaskAggregate and the DealTaskCreatedEvent would be applied.

Any insights on a possible solution would be greatly appreciated.

Thanks,
Bruno

Hi Bruno,

Given your design decision to go with a DealAggregate containing a collection of Tasks you are now wondering how to build the history log of a Deal as well as of an individual Task.
Both are query models. The history log for a Deal is basically all events stored in the EventStore for that Deal. However I doubt I would rely on the actual EventStore to build your UI.
I think you are better of to create a dedicated read model (e.g. plain SQL tables) for the history log of a Deal. With this query model you won’t need to deserialize events on the fly, and you can easily filter relevant events. This query model could potentially also be used for the history log of an individual task.
If the UI screens for both history logs are too different, build a separate query model for each.

As for the 2 options to create a TaskAggregate: if the purpose of the TaskAggregate is merely to facilitate data access for the history log then don’t do it. Just stick to the query model as described above.

Cheers,
Benoît

Hi Bruno and Benoît,

Not sure if this is all to valuable, but I agree with Benoîts stance of how to approach your issue.

Just add specific Query Models for both, which you update in an Event Handling Component (e.g. a Spring Component with @EventHandler annotated functions on it for the events you’re interested in) for the specific use cases you’ve got.
Doing that also means that neither of the two options you suggest for adjusting your Command Model (your Deal Aggregate and Task Entity) is necessary.

That’s my two cents at least.

Cheers,
Steven