I am currently designing and implementing a framework using Domain Driven Design
concepts.
I am trying to put the Validation
in the domain model layer.
Sometimes doing validation needs to access the database and query it, as an example :
"querying to check multiple column unique index"
With respect to this and the fact that queries should be written in the repository layer classes, It comes out that domain entities need to have references to their repository interfaces in the domain model layer in order to put the validation completely in the domain model layer.
I wonder if It is ok for domain entities to have access to repositories ?
And if it is not ok then how should this situation be handled?
I mean should such validation methods be moved to repository
or Application Service
Layers? If yes, is It ok to move the validation methods to those layers ?
Or as domain services can have access to repositories, should we create domain services
in the domain model layer
for validation?
How should we handle It?
thanks in advance
Not really - it creates a dependency tangle among your components.
The architectural expectation is that an aggregate, when loaded, has all of the state information needed to protect its invariant. Any other state involved in a modification to the aggregate should be passed in as an argument.
So the need to query something outside of the aggregate boundary suggests that there is a flaw in your design (the constraint you are trying to enforce isn't "real", the aggregate boundary is drawn in the wrong place, etc).
Using a domain service to support the query that the aggregate needs is better than connecting to the repository directly, but not a whole lot better. The domain model is supposed to be isolated from the environment, but introducing a domain service (or a repository) to support validation binds the domain model to the process boundary.
An acceptable alternative, which may fit your needs, is to have the application fetch the necessary data from the repository and then pass a representation of that data (or a domain service that provides access to that data) to the aggregate, which can then use it for "validation".
Note that you have a consistency issue - some other aggregate can be changing the remotely located data while you are using a stale copy of it to "validate" your own changes. If your aggregate boundaries are correct, the cost to the business of an inconsistency here should be "small".
The key takeaways being that state retrieval and state validation are separate concerns, and understanding that any state that an aggregate does not control is necessarily stale -- separating retrieval and validation in time doesn't add a new race condition to your system. So leave the data retrieval in the application component, put the validation in the aggregate, and accept the tradeoff that you are working with stale data.