EDIT:
To make my question more clear, assume the following Structure:
- A command comes accross the wire. It should be a stable contract that should not change if I change my domain (write) model. So it should not contain any value objects from it. So it contains kind of dtos instead of value objects or the value object is mapped to multiple fields with primitive types.
- The command is taken by a command handler in the application layer. This loads the aggregate from a repository, dispatch the command to the aggregate root and then stores the aggregate in the repository. When dispatching the command to the aggregate root, a conversion has to be done from primitive types to value objects cause I don't want that conversion to be done in the aggregate root. It's no domain stuff.
- The aggregate root makes some validations (is the operation valid in the current state), calculations, calls DateTime.Now or whatsoever. Then it fires an event. THIS IS MY MAIN PROBLEM.
- An event handler takes the event and applies it to the aggregate root. Here again the primitive types/dtos must be converted to value objects cause I do not want to do that in the aggregate root.
- The event is published and stored and should not contain any value objects from the domain because of the same reasons as the commands. They are a contract for e.g. the projections of the read model or other event consumers.
The conversion of the commands and events primitive types to value objects could be done in the handlers. But what about the CREATION of the event in the aggregate root?
I see 2 possible solutions:
- The creation (and publishing) of the event is done by some kind of injected abstract factory that takes value objects and converts them into the events.
- The aggregate root creates and publishes events with value objects and this events are then converted to the domain value object free events outside of the aggregate.
While 1. makes you implement a complex factory, 2. implies implementing all events in 2 versions plus a converter between them.
If we go with 2. I had the additional idea to make a whole second layer of (domain)commands(and handlers) and (domain)events(and handlers). A layer of commands and events that contain domain value objects and are dispatched/created to/by the aggregate root and in the applicaionlayer converted to "contract" commands/events without any (write) model value objects.
Is there any other solution/simplification? Which way would you go?