Dave Donaldson
Critical thinking in software development
NHibernateRepository
Wednesday, November 08 2006
Over the last 15 months or so I've become a big fan of O/R mappers, and NHibernate in particular. James and I successfully put NHibernate in place for a major project that we worked on together (and that he's still working on) and to this day there are still no stored procedures to be found for that application, and performance is as it should be. Our decision to use NHibernate was probably the single best architectural decision we made.
Early on when we first started really getting into NHibernate, I remember James came across a blog post from Scott Bellware in which Scott gave a presentation on NHibernate and in his sample code he had a class named Repository, which was basically a wrapper on top of parts of the NHibernate API. We found his Repository class extremely useful because like a lot of other open-source projects, the NHibernate API is a bit messy and confusing in some places. So we grabbed the Repository class, modified it a bit for our project, and never looked back.
That is until I started on my current project. You see, from an architectural perspective, my current project is very, very similar to the project I worked on with James. And as I'm sure you guessed, we will also be using NHibernate on my current project (except this time the backend database is SQL Server 2005 instead of Oracle 10g). This has allowed me to revisit the trusty Repository class and do some refactoring that we never got around to doing on the other project.
There were a few improvements I wanted to make. The first one was to remove the hardcoded assembly names (the ones where the mapping files and entity classes are defined) from the Repository class and make them configurable. The second improvement was to make the API a little more robust, and provide an even cleaner and simpler way for developers to interact with data through NHibernate. The third area of improvement was to make the Repository class work with generics, and in fact, the new version works strictly with generics so that you need .NET 2.0 to use it (sorry .NET 1.1-ers). And last but not least I wanted to take all these improvements and simply turn the Repository class into its own standalone class library.
So without further adieu, I give you NHibernateRepository, a standalone, configurable .NET 2.0 assembly that you can use out of the box to make using NHibernate extremely simple and lightweight. The current version of the NHibernateRepository works with NHibernate version 1.0.2 and exposes a much-refactored Repository class that is written entirely in C# 2.0 to make heavy use of generics, as mentioned above. The download for NHibernateRepository includes all binaries, source code, and a sample configuration file.
And now that you've downloaded NHibernateRepository, allow me to expand upon its configuration and API.
Configuration
To use NHibernate as-is, you have to configure it in two places: declaratively in a configuration file and programmatically in code. That always bothered me, so I made NHibernateRepository require its own configuration that compliments the NHibernate configuration, thus ensuring the overall configuration is done in one place. The NHibernateRepository uses its own config section and allows you to specify any number of assemblies that contain the NHibernate mapping files and entity classes. In the example below, the Company.App.Entities assembly contains the entity classes and the Company.App.DataAccess assembly contains the NHibernate mapping files.
<configuration>
<configSections>
<section name="repository"
type="NHibernateRepository.ConfigSectionHandler, NHibernateRepository" />
</configSections>
<repository>
<assemblies>
<assembly name="Company.App.Entities" />
<assembly name="Company.App.DataAccess" />
</assemblies>
</repository>
</configuration>
API
In keeping with Scott Bellware's original name, the NHibernateRepository assembly exposes a public class named Repository, which contains the following method signatures (among others):
public static T Get<T>(object id)
public static T GetByProperty<T>(string property, object value)
public static R GetProperty<T, R>(string property, string idName, object idValue)
public static Collection<T> Find<T>(string hql)
public static Collection<T> Find<T>(string hql, object value, IType type)
public static Collection<T> Find<T>(string hql, object[] values, IType[] types)
public static Collection<T> FindAll<T>()
public static Collection<T> FindAll<T>(OrderBy orderBy)
public static Collection<T> FindAll<T>(OrderBy orderBy, int maxResults)
public static Collection<T> FindByProperty<T>(string property, object value)
public static Collection<T> FindByProperty<T>(string property, object value, OrderBy orderBy)
public static Collection<T> FindByProperty<T>(string property, object value, OrderBy orderBy, int maxResults)
public void Save(object entity)
public void SaveOrUpdate(object entity)
public void Update(object entity)
public void Delete(object entity)
public void BeginTransaction()
public void CommitTransaction()
public void RollbackTransaction()
The Difference Between Gets and Finds
When refactoring the Repository class, I wanted to make sure there was a clear distinction between methods that retrieved a single entity and methods that retrieved a list of entities, so I simply borrowed the convention from NHibernate itself:
- "Get" methods: returns a single entity, or null if the ID doesn't exist
- "Find" methods: returns a list of entities, or an empty list if there are no matches found
If you're familiar with the underlying NHibernate API you might have noticed that there are no "Load" methods in the Repository class. The Load method for NHibernate is the same as the Get method, except it throws an exception if the ID doesn't exist instead of returning null. I disagree with that practice, so I've intentionally not provided any "Load" methods on the Repository class.
Also, notice that I said "Find" methods return an empty list instead of null if no matches are found for the entities you're trying to retrieve. This is a slight change in practice for me because I would normally return null in those cases, but reading through the "Framework Design Guidelines" changed my mind (most developers expect to just foreach through the list without first having to perform a null check).
Why Some Methods Are Static and Some Are Instance
You probably also noticed that all the "Get" and "Find" methods are static members of the Repository class, while the Save, SaveOrUpdate, Update, and Delete methods are instance members. This is intentional and for a very specific reason: the Save, SaveOrUpdate, Update, and Delete methods require a transaction context, while the "Get" and "Find" methods do not.
The prevailing thought behind this is if all you need to do is query the database, it should be in as little code as possible. For example, if all you need to do is retrieve a Customer entity, then you should be able to do something like this:
Customer customer = Repository.Get<Customer>(customerID);
I don't know about you, but you can't get any simpler than that. No need to open and manage an NHibernate session or transaction. You just get the data and you're off on your merry way. However, operations that require data manipulation (i.e. an insert, update, or delete) should be performed within transactions, and the NHibernateRepository forces you to do this. In fact, it will throw an InvalidOperationException if you try to manipulate data without a transaction.
Disposing Resources
Because the Repository class ultimately deals with an unmanaged resource, the database, it implements IDisposable and provides a destructor. This means you should use the Dispose Pattern when using instance members of the Repository class. For example, to update a Customer entity in the database, save yourself a few lines of code and write your code like this:
using (Repository rep = new Repository())
{
rep.BeginTransaction();
rep.Save(customer);
rep.CommitTransaction();
}
OK, I think that about does it for now. The NHibernateRepository is really a culmination of over a year of real work on a real project with great success. Many thanks go to James and Geronimo for our many discussions about NHibernate and of course to Scott Bellware for his original Repository class. What I've showed here today is just the next logical step from what he did back then.

19 comment(s) so far
Nice, Dave. I was a tech reviewer for an upcoming book on NHibernate a few weeks back, but having no experience with it prior, and a lot of the config stuff and verbose code seemed to be a bar to entry to me. This seems to sweeten up the pot a bit and may be just what I need to finally get me to give NHibernate a try.
Have you looked at Ayende's Rhino.Commons? svn.sourceforge.net/.../rhino-commons
Dru - Nope, I hadn't seen the Rhino.Commons stuff. I'll have to check it out.
Great! We will start using this in place of our home grown wrapper.
We also use NH extensively and i best thing we did is using Castle project's NHibernateIntegration facility....
- xml configuration
- multiple SessionFactories (databases)
- session and transaction management
Checkout www.castleproject.org/.../index.html
I'm not familiar with repositories so the question might be dumb. Where do you place repository classes? Int the BLL or DAL?
Ivan - Repositories should go in the DAL.
Can there be a wrapper method which can take multiple parameters (with multiple AND/OR) in the WHERE clause? I am actually looking at a variant of Repository.FindByProperty() which could take the WHERE clause as input and build an ICriteria inside it which in turn would fire a query as (for e.g. Please forgive the impractical query.)
"SELECT firstname, lastname, emp.sal, emp.role .... from emp where ((emp.sal < 10000 and emp.role = 'PM') or (emp.role = 'PA') )
There should be an abstraction for specifying the WHERE clause (as in the example above) outside the wrapper method without using HQL or ICriteria outside the wrapper methods. Inside the wrapper method, the WHERE clause should be built as part of the query using ICriteria. I am aware that the SESSION object has been exposed so that an ICriteria can be built outside the method. But I am basically looking at abstraction and dont want nHibernate related things to be exposed outside the Wrapper.
If implemented, this would be a great feature.
Indrajeet - Thanks for the suggestion. I'll see about adding something like that in a future release.
Dave,
Very nice post, we have created a similar repository. It is very much like yours, I have really like how you are added config section and order by in your version, I think we will update our version to match it.
We have slightly different approach on Find, instead of having several arguments in the method we have decided on the wrapper class approach. govorin.blogspot.com/.../nhibernate-repo />
Dave,
I am sorry for having missed out on thanking you in my previous post for this nice wrapper.
Its very good work indeed.
Ok so the repositories goes in the DAL and the client of the repositories goes in the BLL then?. Is it ok to make queries with hql from the BLL? I feel confused about how to fit this in? It always ends up with the entities in a shared namespace between the BLL and the DAL and I really don't want that. I want them to be present in the BLL.
Hi Ivan,
Yes, the "client" of repositories (which should go in the DAL) is usually in the next layer up, typically the BLL. You could certainly construct your HQL in the BLL then give the HQL to the NHibernateRepository to do the data access. Or you could abstract all HQL into their own DLL classes and go that route, which is what I usually do.
As for entities, my entities are usually in a seaprate namespace all to themselves, and many times in their own assembly. This way the DAL and BLL just use them as they see fit.
If I'm not using a service layer between the UI and the BLL I would end up with dependencies to the Entity assembly from every layer. Wouldn't that be kind of hard to maintain? I'm new domain driven design as you probably notice :)
Ivan,
First, let's make sure we're on the same page. When I say entity, I'm referring to a class that contains only state (i.e. properties) and not behavior (i.e. methods). I know this makes some OO blowhards cringe, but it's a very effective implementation of domain-driven design.
With this approach, it's perfectly acceptable (and expected) for each layer in the app to depend on the entities assembly. Afterall, why wouldn't they? Meaning, the "Customer" entity you use in your UI should be the same "Customer" entity in your BLL and DAL (unless of course, you're creating a lightweight, display-only version of the "Customer" entity, in which case it would be a different entity altogether, but I digress).
Your static Get methods dispose of the ISession in using blocks. Doesn't this preclude lazy-loading? I'm new to NHibernate, but I think the session needs to be open for lazy loading to work.
What Jamie said...
Im taking the error "Could not initialize proxy - the owning Session was closed." when I try load a object that have a propertie class.
Ex. object User.Country
or User.Country.Code
or User.Country.Flag
Country is another class...and isnt loaded with Get method.
I’ve never actually written a “Top X Posts” post to end the year before, so I figured, what the heck, I’ll do one this year. As Phil points out , “I find that somewhat narcissistic, so you know I’m going to do that”.
I’ve never actually written a “Top X Posts” post to end the year before, so I figured, what the heck