views:

81

answers:

2

If you have two repositories dealing with persistance to a relational DB, a personrepository that deals with "Person" objects, and an addressrepository which deals with "Address" objects, and a person object has a collection of addresses (probably lazy loaded). Obviously the personrepository would be used to persist changes to the person objects and addressrepository would be used to persist changes to the address objects, but what would be responsible for persisting changes to a persons address collection?

What strategies are available for persisting modifications to a person objects address collection back to the database? And where would that responsibility lie in the repositories(would it be the personrepository even though in the db it would be the addresses that stored the link to a person)?

I should mention that this is not using an ORM.

Thanks for any assistance, any strategies/clarification would be appreciated.

+4  A: 

A bit food for thought:

There are really two questions you need to answer before you decide how to address the problem:

  1. Can an Address exist without a Person?
  2. Can an Address be owned by more than one Person?

If the answer to 1. is no and the answer to 2. is no - you shouldn't have an AddressRepository and Person should be responsible for saving the Addresses in a normal 1-to-many relationship with a foreign-key in the Address. Otherwise, Person is suddenly responsible for deleting Addresses - or needs a reference to the AddressRepository - which IMO would end in a terrible mess of responsebilities.

If the answer to 1. is no and the answer to 2. is yes - you have a many-to-many relationship and Person should maintain this many-to-many relationship (as that is the only one with the knowledge needed to persist it).

If the answer to 1. is yes and the answer to 2. is no - Address should be responsible for updating the relationship - and should have a Partner property, so the association in the objects is uni-directional.

And lastly - if both are yes - You again have a many-to-many relationship, but this time it would be more reasonable to let the Address handle the many-to-many association.

I hope this helps you decide :)

Goblin
Thanks for such a thorough answer :).
grrrrrrrrrrrrr
+3  A: 

Goblin is correct, there is very few scenarios I can imagine which would call for an AddressRepository you probably want to get rid of it.

That being said, the design concept you want to look up is that of an "Aggregate Root". Very quickly this means to identify objects in your object graph without which other objects cannot exist. These are the classes that need repositories and they will end up being the gateways to your object graph.

This was a confusing to me when I first learned about it - I didn't think it would be so simple to identify these objects. The way out is the additional concept of "Bounded Context". This is probably the most under-applied design principle.

In short, consider that you're solving the following two user stories.

  • As a user I want to be able to the website to store all previous shipping addresses so that I can access them easier when placing an order
  • As a logistics administrator I want a print-out of all addresses we need to ship to tomorrow so that I can plan shipping routes accordingly

So you've got something like the following model: Person has Addresses and Orders and Order has an Address

It would seem this might be difficult to dissect. If Person is the root then when a user is simply changing their information we would have to load up the Person object with the Orders association. If they place many orders (say they manage inventory for their company) this could become a huge performance problem.

Selecting Order as the Aggregate Root doesn't solve the problem either. If an Order does not have a reference to a Person then how will we be able to check whether the selected Address is valid?

An aside: The old-school answer to these problems are "lazy loading" and "a bi-directional association" respectively. However both of these techniques come with their own host of complications and I'm convinced that they are usually more trouble than they're worth.

The resolution to this seeming conflict (why do I feel like I'm channeling Eliyahu Goldratt?) is to acknowledge that the two stories exist within different contexts of meaning. When the user stores an Address they don't care about orders, likewise when an administrator is examining addresses they don't care about the person it's for. There is a conflict of definitions. When the two contexts say "Address" they are referring to the same physical object but only as a touchstone for two very different concepts! As far as the person is concerned an address is just a block of test that they've stored. As far as the logistics manager is concerned the only requirement for an address should is that correlate to a real location.

So why even have them be the same object?

Person has PreviousAddresses and Order has ShippingAddresses of which one is selected

Do you see what's happened? You've broken the problem down to two discrete and unrelated systems and, as we all know by now, small, discrete, and focused systems are the key to maintainable software.

So what happens when these contexts need to communicate? Since the address objects in the two contexts are likely to be used at different times (and one of them is read-only) it would be conceivable to use the same database. This however, is not recommended (though many people do it anyways). Instead the communication between the two domain contexts should be handled in code via an explicit messaging and mapping mechanism such as an event aggregator/messaging bus (if anyone knows the difference between the two do tell).

George Mauer
What are You using to draw those fancy images? :)
Arnis L.
Wish I could mark more than one answer as correct, thanks for another good answer.
grrrrrrrrrrrrr
@Arnis L. These are all from yUml.me , sometimes websequencediagrams.com too
George Mauer