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.