Repository is set up to get ARs by their ID from the event store.
That should suffice. If you need to query a collection of
ARs from the repository you should use a specially designed
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.
Has anyone done this before, and how did you do it?
I create a fast, light, specially designed Read model that answers to this question only:
bool isThereAlreadyAProductWithThisCode(string productCode).
Do I need a read model first?
Yes. See above.
Should I query the read model, then use a resulting ID to get the AR from the event store?
Only if you need to send commands to it. Aggregates have only command methods (no query method whatsoever).
What if I need multiple AR results to be returned?
Then create a new one or modify the above Read model to answer to this query.
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 :(
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 the
Aggregate, with its entry point, the
Aggregate 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 called
snapshoting 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.