views:

52

answers:

1

Let's say I have a Farmer class, and a Farmer has a collection of Pigs.

If I use an ORM like Hibernate, I can cascade updates to a Farmer's Pig collection, such that I can do something like this from my controller:

Pig pig = new Pig("Charlie");
farmer.addPig(pig);
farmerService.save(farmer);

My farmer service doesn't know anything about Pigs. Depending on the requirements of the application, I might not even need a Pig DAO at all. I'm only concerned with Farmers.

Cool, but what happens when a Pig gets turned into bacon?

farmer.removePig(pig);
farmerService.save(farmer);

The problem here is that in a stateless web application I need some way to create a Pig that I'm going to pass to a Farmer's removePig method.

I could do:

// manual search Farmer's collection - requires loading all pigs.
// Yes, I could just pass id to removePig, but it confuses the example
pig = farmer.getPigById(id);
farmer.removePig(pig);
farmerService.save(farmer);

or

// loads up a pig, and hopefully it belongs to the farmer
pig = farmerService.getPigById(id);
farmer.removePig(pig);
farmerService.save(farmer);

The latter seems better, but if I'm going to add a getPigById() method to my farmerService, I might also just have a savePig() method. This would change the focus from the Farmer to the Pig.

pig = farmerService.getPigById(id);
farmerService.removePig(pig);

Aha, and look it's even less code. However, it violates the logical view of wanting to work with Farmers and their pig collections, not individual pigs. I'm no longer explicitly removing a Pig from a farmer, it's all implicit and backwards.

I seem to run into this problem a lot. The class that should be in focus is Farmer. Pigs are secondary. But it's hard to work with collections of Pigs without sliding down the slope into working with individual Pigs whose changes are simply reflected when Farmers are reloaded from persistence.

What advice can you offer me in this matter?

+1  A: 

In the scenario I tend to lean toward your 2nd approach. The fact that you are in a state less environment should not be reflected in your object model, only in the way that you restore your state in a particular http request. This is done here:

pig = farmerService.getPigById(id);

This code should occur in the controller (within MVC or MVP pattern). Then the rest of the code continues as you normally would:

farmer.removePig(pig);
farmerService.save(farmer);

The particular controller that is handling the current request should be responsible for maintaining this state of the current pig being considered. It should be responsible for sending a pig id to the browser, and responsible for translating this pig id into a pig object. The way it does it is its own, but using the call to the farmer service makes the most sense. From here, you can further automate this translation by having a general id-to-object call and vice-versa.

Your thinking that this domain model should be farmer focused is correct and goes inline with domain driven design. The Farmer class in this case is an aggregate of pigs, and therefore defines a boundary around a set of pigs. All pig access should go through farmer. In this way you have a clear contract of how pigs are created and destroyed and modified. Therefore your last approach is not as sound as the one before.

eulerfx
This makes a great deal of sense to me, thanks!
Boden