Persistence Ignorance and Associations
One issue that seems to come up regularly in the team I'm on is how to design associations between persistence ignorant domain classes, or more particularly how to do it without falling into bad design practices.
Let me provide an example of the sort of problems that come up. Let’s say we have an abstract Company class which is the base class for two concrete classes:
- Agency - Contains a collection of Clients.
- AgencyNetwork - A collection of agencies that work together.
A Client is associated with one Agency and an Agency has 1+ Clients. An AgencyNetwork is associated with 1+ Agency objects, with each Agency in 0 or 1 AgencyNetworks.
The original solution is much like this (I've simplified it to show in a class diagram):
The reason the associations are like this is that we're managing the relationship from the "one end" as its simpler. Now here is what I don't like about this design:
- AgencyNetwork is currently only used by one of our application so having our key Client class indirectly coupled to it seems like a very bad idea. I'd prefer our core classes, which the majority of our applications will use, to be coupled to as few non-core classes as possible.
- I'd prefer if our design made it clear what the real world associations were, I don't think this design does.
- I don't like the idea that the way you find out if an Client is in an Agency is like this: if(Client.Agency != null).
- As I see it in a lot of the time you'll want to use an Client without knowing about a Agency/AgencyNetwork but if your working with a Agency it's likely that the first thing you'll want to do is manage the collection of Clients.
This is my alternative soluton:
Although I think its much better this solution it is not perfect either (things never are).
In object oriented terms I prefer it as Client isn't coupled to the other two. I also think that when you get an AgencyNetwork the first thing you'll want to do is look at the list of companies in it. In addition I believe that the associations are far more natural, they reflect the real world associations far better.
The disadvantage of the second solution is that managing the relationship becomes more complex. With the first solution you could do this:
// change Clients Agency
client.Agency = newAgency;
// if the Agency is in a AgencyNetwork take it out of it
client.Agency.AgencyNetwork = null;
Personally I think this is incredibly ugly and does not reveal the intention very clearly but it is short.
With the second solution its more complex, not least as the Agency now handles the association so you have to do this (note we’re using the repository pattern here):
AgencyRepository agencyRepository = new AgencyRepository();
Agency oldAgency = agencyRepository.GetForClient(Client);
oldAgency.Remove(Client);
newAgency.Add(Client);
Although it involves more code I think this is much clearer, however where do we put this code. We cannot put this in the domain assembly as we don't want our persistence ignorant domain layer to access repositories. We'd therefore need to do it in the domain coordination layer:
public static void ChangeClientsAgency(Client client, Agency newAgency)
{
... as shown above
}
The question is thus which solution do we prefer:
a) Solution 1 - Have the one end (which will often be one of our key/core classes) manage the relationship and so enforce things that way (resulting in a lot of coupling).
b) Solution 2 - Decouple the classes, add the associations that we think make most sense and then have to explicitly manage the relationship.