How *not* to inject services in entities
I’ve seen lot of people asking where and how to inject services in entities. The services in question are often repositories by the way…
The response is simple :
- DO NOT inject services in entities !
- Ok I see, you’re against dependency injection
- NO, I'm not against dependency injection, I use it a lot.
- You can still use a static service locator…
- I avoid service locator when I can, especially when the service locator must be static…
– So you’ll get an anemic object model !
- I don’t think so.
Injecting services in entities is wrong
You’ll find me a bit presumptuous, but I say it again : Injecting services in entities is wrong.
Nesting objects is not a problem from an OO point of view, but we’re talking about a special kind of objects, entities.
Entities are all about their state management, and this state management can require several objects.
- Code infrastructure objects like lists or dictionary to handle collection of data,
- Object oriented constructs to leverage code maintenance techniques like strategies.
Entities don’t have to be classes with public setters and getters… you should even avoid this to keep you entities in a consistent state.
But there is no reason for an entity to keep a reference on a service, since it’s not part of its state.
There are usually three situations in which people thinks they need it :
- Lazy loads
- Relations
- Behavior methods
Let’s review each point…
Lazy loads
Sometimes, an entity property is heavy to load and is not required by all code paths. In this case, loading it upfront can lead to performance problems.
The usual way to work it out is to hold a reference to a data access object or a repository and to load and cache the requested data on demand.
Using a data access layer object in the entity is clearly a break of persistence ignorance, but using a repository is not a better option.
The repository is a way to abstract persistence in the model, but it’s still a persistence concern even if modeled in terms of domain terms.
I’ve already posted about ways to solve this problem in Lazy load and persistence ignorance and part 2.
Relations
I was twitting yesterday with Kyle Baley about the need to have an Event repository in the Users entity. He wanted to get the User Team for the current event. I think you don’t need more context to understand the problem.
The User did not know about the current event so it needed the Event repository to find it and find the corresponding team.
But why does the User entity expose a CurrentTeam property if it doesn’t know about Events ? There’s something missing here.
The whole picture becomes clearer if you add a Participant entity that embodies the participation of a user to an Event, and no repository is needed anymore since you don’t need a CurrentTeam property on User.
Make relations clear instead of hiding it in repositories.
Behavior methods
If I have mail message entity and I want a Send method on it ?
Tiding your entity to the service that will use it is not conceptually satisfying. The server that will send the message is a medium and is not part of the entity itself.
It’s seems better to call server.Send(message).
The problem is that you can end breaking the tell don’t ask principle because the Send method will ask the message for each property value. And you can be tempted to put computations that should be in the message entity inside the Send method.
Let’s call Double Dispatch to the rescue !
- Design a server interface presenting a Send method that take the parameters it need (title, recipients, message body…)
- Add a SendThrough method to your entity that takes the server interface as parameter
- Implement SendTrhough so that it computes values to pass to the Send method
- That’s it.
Here is a small sample implementation :
public interface IMailService
{
void Send(string sender, string recipient, string subject, string body);
}
public class Message
{
//...
public void SendThrough(IMailService mailService)
{
string subject = isReply ? "Re : " + title : title;
mailService.Send(sender, recipient, subject, GetMessageBody(content));
}
}
The entity is not tied to the service before needed. So no need for injection.
Is injection useless ?
There is no problem to inject services with other services, and it’s even easier since services have no state, they only need their dependencies in constructor, and to my opinion it’s the cleanest injection mode.
Usually domain services will need infrastructure services dependencies, and in this case a dependency injection framework can make things easier.
Following the preceding advice, you’ll never need to use your dependency injection framework as a service locator, and you’ll never have to perform buildups on your entities, and you’ll feel much better.
What’s your way to deal with it ?
For now I’ve always find a way to get rid of services inside entities, but I really would like to hear cases where you’re stuck with it to see if another way is possible, or cases where you think there is really a good reason to go this way.