Should you inject, or even use repositories in you entities ?
The response is two fold, and both go in the same direction, you shouldn’t.
Of course, we’re discussing design here, so if in your specific case you find reasons more important than those invoked here, there’s always a possibility to decide to go as you wish…
Injection and DDD patterns
Where talking Injection and Entities/Repositories here, so the first reason concerns what injection means in a Domain Driven Design environement.
The wikipedia definition of the dependency injection pattern only makes references to objects or components without defining explicitly which kind of object or which kind of component…
But a famous injection anti pattern can give use more information on what are injected components.
I call the Service Locator anti pattern.
This make it clear that what we are looking for is a way to find service in a supple and configurable way.
I won’t explain here why the service locator is an anti pattern, but it makes it obvious that the use of injection is to provide access to services in the code.
Since services are supposed to be stateless, their lifecycles are usually quite flexible. A service could be instanciated on each call, on each request or as a single instance without much difference. The injected service dependencies enable to compose services to replace implementations by configuration or for tests..
But even at runtime. A live configuration change could indicates to replace an injected service on next instantiation.
Services and repositories are quite obviously not injected with Entities/Aggregates:
- A repository is here to instantiate entities, it’s its own job, it doesn’t need to be injected with entities…
- When a service needs an entity, it can be injected with a repository, and get the entity through it.
But could entities be injected with services or repositories ?
An aggregate or an entity is not stateless as a service, it is statefull, and its member fields are here to maintain current state.
It seems quite odd to use those fields to store references to services that are obviously not part of the state.
It also links the referenced service lifecycle to the lifecycle of the entity itself.
Most entities instanciation schemes in web applications are on a per call basis, and since most web application don’t do anything between calls, the response to the lifecycle problem is simply that everything in created and destroyed on each call.
But it is only a specific simplistic way to consider object lifecycle. What if you kept your entities longer in memory and reused them on next call to avoid roundtrips with the data storage ?
Having a reference to a service inside an entity state would make the live reconfiguration far harder to achieve : You would have to trash all current state and reload everything. There is no such problem with services since they’re meant to be stateless.
Entities fields are meant to store state, no to reference services. Their lifecycles should not be coupled.
The second reason is about the aggregate consistency boundary.
Why would you typically need a reference to a repository inside an aggregate ?
First reason would be to load sub entities when needed. It’s also called delay load.
You shouldn’t need delay load in aggregates
The reason comes from the aggregate definitions. From wikipedia:
Aggregate: A collection of objects that are bound together by a root entity, otherwise known as an aggregate root. The aggregate root guarantees the consistency of changes being made within the aggregate by forbidding external objects from holding references to its members.
The definition talks about object being bound together. Those objects – entities – have strong relationships, or grouping them in an aggregate makes little sense. When the relation is strong, you will need for each
aggregate method to change all objects in coordination, or none. If not, parts of your aggregate should not be here.
If an aggregate needs all its state for each operation, there is strictly no reason to use delay load.
Load all, use all, save all.
The second reason would be to load entities in other aggregates.
You shouldn’t need references to entities in other aggregates
or at least not directly. The service calling the method on the aggregate will find information needed to call the method (which can contain information coming from other aggregates), but if you need a direct reference to another entity, it’s a clear indication that the aggregated boundary is wrong ! Put that other entity in the aggregate !
Thus once your aggregate modeling is ok, there is really no reason to use a repository inside an entity.