I have a Aggregate Roots that use the event sourcing technique of being built from a series of events in a Repository. This is all great for when I just need to manage change of state etc, but when I come to using the Specification pattern to apply my app specific business rules, I am hitting a wall on what Entities to use, how to instantiate them etc etc.
I would want to run specific methods on my Repository, for example getProductByProductCode
so I can check my current AR against it for uniqueness (simple example), but I am unsure how to do this, as my Repository is set up to get ARs by their ID from the event store.
I used to have a database backing my Repositories, now I only have an event store as I have no read models yet.
- Has anyone done this before, and how did you do it?
- Do I need a read model first?
- Should I query the read model, then use a resulting ID to get the AR from the event store?
- What if I need multiple AR results to be returned?
I am so confused as I thought I was doing it all the right way now as we need event sourcing, but I can't seem to marry up my old-school thinking with how to do it now it's event sourced 🙁
Best Answer
That should suffice. If you need to query a collection of
ARs
from the repository you should use a specially designedRead model
.Put it another way, you are using CQRS. This means that you cannot query the Aggregate to check it's
product code
and it's natural that you cannot query the repository either, which basically its a collection of Aggregates.I create a fast, light, specially designed Read model that answers to this question only:
bool isThereAlreadyAProductWithThisCode(string productCode)
.Yes. See above.
Only if you need to send commands to it. Aggregates have only command methods (no query method whatsoever).
Then create a new one or modify the above Read model to answer to this query.
It is hard because there are two leaps that you must take:
CQRS: there is a write model that only receive commands (methods that return
void
). It does not have any query method. In DDD, this is theAggregate
, with its entry point, theAggregate root
. There is also one or more Read models. They have query methods that answer any question from the other layers (i.e. Presentation, Application, Infrastructure). They have also methods that update their persisted state when events happen but these methods are not to be used by the other layers. After the events are applied to all the Read models, they are discarded (not used any more by the write side). When a command arrives, the Aggregate is loaded from a Repository where its plain state was persisted when the last command was handled.Event sourcing: the write model, in DDD the Aggregate, has no plain persisted state. Every time a command arrives, the Aggregate is rehidrated by the Event store by
new
-ing an Aggregate's class and then applying all its own previous emmited events (there is an optimisation calledsnapshoting
but it acts just like a cache and it should be avoided if not really necessary). There is no database containing the Aggregates state other than the Event store.