NHibernateRepository
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.
Similar Posts:
-
http://www.danhounshell.com/ Dan Hounshell
-
dru
-
http://www.arcware.net/ Dave
-
http://brianhprince.blogspot.com/ Brian H. Prince
-
Michal
-
ivan
-
http://www.arcware.net/ Dave
-
Indrajeet
-
http://www.arcware.net/ Dave
-
http://govorin.blogspot.com/2006/11/nhibernate-repository-variotion-on.html Alexei
-
Indrajeet
-
ivan
-
http://www.arcware.net/ Dave
-
ivan
-
http://www.arcware.net/ Dave
-
Jamie Ide
-
Gferreira
-
http://arcware.net/my-top-5-posts-of-2008-sort-of/ My Top 5 Posts of 2008, Sort Of
-
http://feeds.feedburner.com/~r/arcware/~3/499496811/ My Top 5 Posts of 2008, Sort Of



