views:

62

answers:

2

I have a chance to introduce NHibernate to my group by using it with some new components that are being added to a legacy application. I'm trying to get my head around using the DAO pattern with NHibernate, and am stumped with an architectural question.

In my fictional example, let's say I have CarDAO and a Car entity:

public interface CarDAO {
    Car FindById(int id)
    ... // everything else
}

public interface Car {
    ... various properties and methods
}

I have a need to be able to convert a car to right-hand drive. Since this would be a very complex operation, I need to execute a stored procedure. I'm not clear on where the ConvertToRightHandDrive() method should go.

It makes sense to me to put the method on Car, and let it call a method on the CarDAO that will execute the stored procedure. And this is where I'm not clear:

  • should Car have a reference to the CarDAO and call CarDAO.ConvertToRightHandDrive?
  • should there be some sort of CarService layer that calls CarDAO.ConvertToRightHandDrive?
  • what about injecting the CarDAO through the method on Car (Car.ConvertToRightHandDrive(carDAO))
  • some other option?

Perhaps this is only a religious argument, and people have differing opinions on whether or not an Entity should have a reference to its DAO (or any other DAO, for that matter). I've been searching StackOverflow for some time, and have seen several discussions around this topic; but, I'd be interested in people's opinions in this particular scenario.

+1  A: 

The way I was always told to think about it is that Entities should have as little in them as possible and that various objects should perform operations against entities. The entities themselves should not be aware of the DAL or they lose their data storage ignorance

So in this case, a CarManager (or similar) which possibly has a dependency on the CarDAO should have a ChangeToRightHandDrive(Car) method.

Oh and one other advantage to having a CarManager which performs the complex operations is that you're not relying on stored procs - This is almost certainly a religious issue but I prefer to have all the logic in my code rather than relying on SPs (There are a few exceptions but usually only around large sets). This means that if you changed to another DAL (say XML), you wouldn't need to re-implement your SP in your DAL/DAO - Otherwise, you'd end up with business logic embedded in your DAL.

Basiclife
Interesting - This was edited whilst I was editing so I've lost the intermediate edits (and it's not visible in the history). Apologies to whoevers edits I wiped out
Basiclife
@Basiclife: Maybe it would be a good idea to mention that problem on [meta](http://meta.stackoverflow.com), too.
Chris Lercher
A follow-on question then...If I create a CarManager, which now has a dependency on CarDAO, should this manager class also have a method to retrieve a Car by Id (just a pass-thru call to CarDAO.FindById())? Should CarManager.GetCar(id) be the primary method of retrieving a Car?
Mark Wilkins
Interesting question - I use entity framework 4 and in my XManager, I have functions for Get(Lambda), Delete(Lambda), etc... which effectively wrap the functionality of the DAO but also allow me to modify the lambdas as they're passed through (for example, all my entities inherit from a common class which has a RecordStatus field. I effectively append an "And RecordStatus=Active" to the lambda in the manager (actually a base manager that all managers inherit from) This allows me to add db-wide and table-wide logic that affects all queries without writing lots of getter methods)
Basiclife
by "Append to the lambda" I do of course actually mean modify the expression tree but I was running out of space :)
Basiclife
+1  A: 

My opinion is that Car should have no knowledge of CarDAO. This keeps your domain model clean and allows you to change your back-end without affecting the Car class.

If you need to call a stored procedure to convert a car to right-hand drive, I like the option of having a CarDAO.ConvertToRightHandDrive(Car car) method and then using something like a CarService class to hide the dependency on CarDAO from any callers (i.e. the CarService class would have an identical method that would just forward the call to CarDAO).

As you mention, people will definitely disagree on this type of thing, but it's always worth carefully considering dependencies and coupling before you start hacking away.

Ben Hoffstein
Thanks, Ben. I would vote up your answer, but I don't have the rep. Grr.
Mark Wilkins
@markwilk Did it for you :)
Basiclife
@Basiclife much obliged!
Mark Wilkins