CQRS – Querying Aggregate Root Using Fields Other Than GUID

cqrsdomain-driven-designevent-sourcing

There are many CQRS frameworks and event store libraries.

All of them use GUID as aggregate root's ID.

Those event store only let me query only by GUID.

I realise that there are many times in last project(DDD+CRUD) I need to query aggregate root using others fields rather than GUID.

Sometime use couple fields.

How to solve this problem?

Should I query read model inside command handler?

Or I need to build another repository to map properties to GUID?

Or I need to solve this problem by redesign the domain models and query things to get GUID before enter command? I asked it here

Best Answer

CQRS/ES is a tricky architecture in many aspects and you've found one of them.

First of all, since you're storing events it is very hard to query an entity based on its data since you don't actually have the entity-state stored anywhere, only the events that will generate such state. It won't work like a regular state-based storage where you can go into your record and query a person from its name, for an example.

So, for the command-side (the ES side) of your equation, you should only be able to reliably fetch a whole entity by its ID and then replay the events to rebuild its final state.

Now, of course, there are business scenarios where you will need to find a person from its name. When that happens, the easiest way to proceed is to simply query the read model and then proceed to fetch the ID to go get the command entity from it. Please be aware that the read-side is subject to a propagation delay from the command-side. That means it's only eventually consistent. Once a command is triggered and processed on the command-side, there will be a random period of time where the read-side will not reflect this latest change, so your code must be prepared for that.

However, you should really try to make your application layer communicate in terms of your entity IDs to avoid this extra step as much as possible and it shouldn't be that hard.

Imagine some client is reading data pertaining to one of your entities. If that is happening, that client probably already holds the ID information of that given entity. So if he wants to send a command to such entity, he should be able to fire it based on its ID and not on other state-based data.

Related Topic