A Journey with NHibernate - Part 1

In this series of articles, I am going to dive into some topics with NHibernate.  There is a lot of beginner information on the internet, but not a whole lot of real-life examples.   I’ve seen countless exaples where the author builds a session factory, creates a session, and does some persistence all inside a single method or block of code.  This is of course ludicrous for real projects.  This is something I’d like to address.  I’ll try to focus on things like proper object-oriented design and testability with your projects.

In the first few articles, we will see how to start projects using NHibernate, go over some basic topics, and then get progressively more complex as we explore the many features of the ORM tool.

If you don’t know what NHibernate is, I’d suggest a google search or going to the NHibernate home page.

…..go ahead, I’ll wait…..

Ok, so you know what NHibernate does, and you’re convinced you want to use it.  What next?  First we have to understand how to “properly” structure your project.

(Side note:  I say ‘properly’ in quotes because some will disagree with me.  There are 2 very distinct camps when it comes to designing domain objects for persistence.  One camp follows an active record (class-in-charge) approach to persistence (such as Castle’s ActiveRecord and CSLA.NET).  These folks prefer to encapsulate all of the persistence inside of the object itself.  I started off with this mentality, but quickly got annoyed with all of the persistence code within my domain model.  I have since sided with the POCO/PI (Plain-Old-CLR-Objects / Persistence-Ignorant) objects where your objects are completely separated from their persistence.  I think this leads to code that is easier to test, less-cluttered, and decoupled from infrastructure concerns.  This leaves only business logic, which is the most important concern to any project.  In this article I am going to focus on PI objects, however most of the content will be relative to an active record approach).

I will start out by creating the project structure:

  • Project.DomainModel (business objects / logic)
  • Project.Persistence  (data access strategy)
  • Project.Utilities  (project-wide utilities)
  • Project.Web.UI  (web front-end, if any)
  • Project.Win.UI   (windows front-end, if any)
  • Project.DomainModel.Tests (tests for the domain model)
  • Project.Persistence.Tests (tests for the persistence layer.)

To ensure that the domain model knows nothing of persistence, I will make sure not to add the reference to the Persistence project or any NHibernate dlls.  Now, we can add the reference to the NHibernate dll to the Persistence project.

The test projects, as you can see, are separated based on what they test.  Why is this?  Because your main tests are going to be testing the logic and behavior of the domain model.  It is imperative that these tests run quickly.  If you keep the slower tests separate, it keeps developers more productive (and more likely to run the tests!).  The persistence tests will actually hit the database, and so they will be *much* slower.  We’ll see this later on.

On any object-oriented domain model, you should try to develop your objects without concern for the database.  That is, develop and test the behavior of your objects before you even go to save them to the database.  There are many benefits to programming this way:

  • Your code is more testable
    Code that doesn’t depend on many things is easier to test.  The data access portion is a large example of this.  You should be able to test object interaction entirely without hitting a database.
  • Your knowledge of the domain increases as you go
    You aren’t ever going to understand every minute detail of an application before you write it.  No matter how much up-front design you do, you’ll always end up getting stumped and running into a road-block, or your understanding of the problem domain will evolve.  This is expected and embraced when you are practicing Test Driven Development.  Your code changes are backed up by unit tests which tell you if the code is working.  If you leave out the database in this loop, you return to a a functioning domain a lot quicker.  Implement the database once your design has settled down some more.
  • Your persistence layer can be substituted with minimal impact to program behavior
    If you decide at some point that you’d rather go with a different ORM, or hand-craft the data access portion you can do that.  You don’t have to worry about your changes affecting program behavior, as long as you fulfill the responsibilities of the data access layer.

I think that we have a good overview of NHibernate and how it fits nicely with Domain Driven Design.  In the next article we’ll get more concrete and actually start a fictitous project using NHibernate and .NET 2.0.

Until next time….