Managing your NHibernate Sessions
Posted by Davy Brion on June 22nd, 2008
I was working on my northwind sample application (which i’ll post about as soon as i get something that’s worth showing) and i was struggling to find a clean way to manage my NHibernate sessions. I wanted a way to create a session once you enter the service layer, and that session should be available transparently to the repository implementations without actually having to constantly pass it around. But i didn’t just want to store it somewhere and have all the classes that needed the current session get it directly from that place. Also, i didn’t want the current session to be available to everyone. Another important requirement was to have maximum flexibility for writing tests. I could just use Rhino-Commons’ implementations of the UnitOfWork and Repository patterns and be done with it, but where’s the fun in that? And since this application is mostly a learning experience i figured i should try to write this myself. After a bit of searching and experimenting, i finally came up with a way that i’m happy with (for now anyways). Let’s have a look.
To illustrate what i want, take a look at this made-up method in my service layer:
public ProductCategoryDTO[] GetAllProductCategories()
{
using (ISession session = GetNewSession())
{
var repository = GetProductCategoryRepository();
var categories = repository.GetAllProductCategories();
return categories.ToDTOs();
}
}
This is just some example code, it doesn’t even work. But it’s kinda what i want… The thing is, i don’t want to deal directly with the ISession type in the service layer, but i do want the ProductCategoryRepository to use the ISession that is created within the context of this method call.
NHibernate’s ISession type is an implementation of the Unit Of Work pattern. I don’t want to use the ISession directly in my service layer because i want something that is a bit more high-level. Basically just something that would allow me to work within an NHibernate session, and provide me with the ability to flush changes to the database whenever i want to. And obviously, i want it to allow me to create a transaction as well. So i came up with the following unit of work interface:
public interface IUnitOfWork : IDisposable
{
/// <summary>
/// Flushes any changes that haven’t been executed yet
/// </summary>
void Flush();
/// <summary>
/// Creates an ITransaction instance with the ReadCommitted isolation level
/// </summary>
/// <returns></returns>
ITransaction CreateTransaction();
/// <summary>
/// Creates an ITransaction instance with the given isolation level
/// </summary>
/// <param name=”isolationLevel”></param>
/// <returns></returns>
ITransaction CreateTransaction(IsolationLevel isolationLevel);
}
This interface pretty much offers me anything i’m concerned with in my service layer. The real implementation would do a bit more though… It has to create an NHibernate session and make it available to the repositories in a clean way. Here’s the thing though… the repositories have a completely different lifetime than the NHibernate sessions. The NHibernate session has to be created when we enter a service method, and it has to be valid within the scope and context of the execution of that service method. The repositories however stay alive for the lifetime of the application so they can’t just hold a reference to an NHibernate session. Every time you call a method of a repository, it has to find out which session it should use, which is the session that is being used in the context of the current service method call. Now, we could always pass around the session but that really doesn’t look good and is cumbersome. So i basically need something that gives me access to the active nhibernate session:
public interface IActiveSessionManager
{
/// <summary>
/// Returns the active ISession for the current thread. Throws exception if there’s
/// no active ISession instance
/// </summary>
/// <returns></returns>
ISession GetActiveSession();
/// <summary>
/// Sets the active ISession for the current thread. Throws exception if there’s
/// already an active ISession instance
/// </summary>
/// <param name=”session”></param>
void SetActiveSession(ISession session);
/// <summary>
/// Clears the active ISession for the current thread.
/// </summary>
void ClearActiveSession();
}
That gives me the ability to retrieve and set the active session on a per-thread basis. After all, a service method call will be handled by one thread, so setting the active session for that current thread is a convenient way to store the session.
Now i still need something that takes care of creating the NHibernate sessions:
public interface ISessionFactory
{
/// <summary>
/// Creates a new ISession instance
/// </summary>
/// <returns></returns>
ISession Create();
}
Ok, so what do we have so far? An interface to define the functionality that a UnitOfWork should offer at the service level. An interface to store/retrieve the active session on the current thread, and finally, an interface to actually create the NHibernate session. Let’s start looking at the real implementations. Here’s the code to the SessionFactory class:
public class SessionFactory : ISessionFactory
{
private readonly NHibernate.ISessionFactory sessionFactory;
public SessionFactory()
{
Configuration configuration = new Configuration()
.Configure()
.AddAssembly(“Northwind”);
sessionFactory = configuration.BuildSessionFactory();
}
public ISession Create()
{
return sessionFactory.OpenSession();
}
}
Pretty straightforward… it initializes NHibernate and gives us the ability to ask for new sessions. So how are we going to make these sessions available to our repositories? Through the ActiveSessionManager class of course:
public class ActiveSessionManager : IActiveSessionManager
{
[ThreadStatic]
private static ISession current;
public ISession GetActiveSession()
{
if (current == null)
{
throw new InvalidOperationException(“There is no active ISession instance for this thread”);
}
return current;
}
public void SetActiveSession(ISession session)
{
if (current != null)
{
throw new InvalidOperationException(“There is already an active ISession instance for this thread”);
}
current = session;
}
public void ClearActiveSession()
{
current = null;
}
}
It basically just stores the session in a ThreadStatic field, which means that each thread will have a different static reference for this field. So if we set the active session through the SetActiveSession method in thread X, and thread Y also sets an active session, the GetActiveSession method will return the correct session instances for each thread.
So now we have everything we need to create our UnitOfWork class:
public class UnitOfWork : Disposable, IUnitOfWork
{
private readonly IActiveSessionManager activeSessionManager;
private readonly ISession session;
public UnitOfWork(ISessionFactory sessionFactory, IActiveSessionManager activeSessionManager)
{
this.activeSessionManager = activeSessionManager;
session = sessionFactory.Create();
activeSessionManager.SetActiveSession(session);
}
protected override void DisposeObjects()
{
if (session != null)
{
session.Close();
session.Dispose();
}
}
protected override void ClearReferences()
{
activeSessionManager.ClearActiveSession();
}
public void Flush()
{
session.Flush();
}
public ITransaction CreateTransaction()
{
return CreateTransaction(IsolationLevel.ReadCommitted);
}
public ITransaction CreateTransaction(IsolationLevel isolationLevel)
{
return session.BeginTransaction(isolationLevel);
}
}
When the UnitOfWork is created, it receives an ISessionFactory instance, and an IActiveSessionManager instance. It then creates a new session through the ISessionFactory and uses the IActiveSessionManager to make sure that session is the active session for the current thread. When the UnitOfWork is disposed, it closes and cleans up the session and it also uses the IActiveSessionManager to clear the active session for the current thread. Oh and it obviously also provides implementations for what it is we actually need in our service layer: flushing the changes whenever we want and creating transactions.
The ISessionFactory and IActiveSessionManager instances should stay alive as long as the application is alive. But as you could see in the implementations of those types, we didn’t write any code to deal with their lifetimes. I’m actually relying on my IoC container for that. In the class where my container is set up, you’ll find the following code:
private static void RegisterUnitOfWorkComponents()
{
Register(Component.For<ISessionFactory>()
.ImplementedBy<SessionFactory>().LifeStyle.Singleton);
Register(Component.For<IActiveSessionManager>()
.ImplementedBy<ActiveSessionManager>().LifeStyle.Singleton);
Register(Component.For<IUnitOfWork>()
.ImplementedBy<UnitOfWork>().LifeStyle.Transient);
}
ISessionFactory and IActiveSessionManager are registered as singleton instances, so whenever these types are requested, the same instances will be returned. The IUnitOfWork type is registered with a transient lifetime, so whenever it is requested, the container will create a new UnitOfWork class and pass the ISessionFactory and IActiveSessionManager instances to the constructor.
Right, we’ve taken care of creating the session, associating it with the current thread and making it available in a nice and clean way. Now we actually have to make sure our repositories can use it. In the base repository implementation, you can find the following code:
private readonly IActiveSessionManager activeSessionManager;
public Repository(IActiveSessionManager activeSessionManager)
{
this.activeSessionManager = activeSessionManager;
}
protected ISession Session
{
get { return activeSessionManager.GetActiveSession(); }
}
Whenever a repository needs a session, it just needs to use the protected Session property and it will get the session that is associated with the current thread.
So now we can rewrite our made-up service method from earlier to the following:
public ProductCategoryDTO[] GetAllProductCategories()
{
using (Container.Resolve<IUnitOfWork>())
{
var repository = Container.Resolve<ProductCategoryRepository>();
var categories = repository.GetAllProductCategories();
return categories.ToDTOs();
}
}
We know that the NHibernate session will be created, and more importantly, that it is not just globally accessible to everyone. It can only be accessed when you have a reference to an IActiveSessionManager instance. We also don’t need to pass around the session all the time so our code is a bit more concise, showing only the intent of what we’re trying to do without distracting us with details that are not relevant to that intent. We also have a lot of flexibility to write tests… i can write tests for my repositories without having to create a UnitOfWork… i can simply pass a fake IActiveSessionManager to my repositories when i’m testing them and have it return the session that i’m using for my test. All in all, this approach offers me with a lot of advantages, without ugly disadvantages. Well, at this moment i don’t really see any disadvantages so if you do see some, please let me know
June 23rd, 2008 at 4:40 pm
I realize the code is illustrative for the sake of clarity. In your production code is Container.Resolve ubiquitous throughout your project?
I’m also a big fan of removing knowledge of ITransaction from my code in UnitOfWork (also taken from Rhino commons)
public void Transact(Action transactional)
{
if (session.Transaction.IsActive)
{
transactional();
}
else
{
using( ITransaction transaction = session.BeginTransaction() )
{
transactional();
transaction.Commit();
}
}
}
June 23rd, 2008 at 6:12 pm
I do have a static Container class which wraps a few of the Windsor container methods, but i only use it in my service layer, or in my asp.net pages to retrieve components. In all other places i try to get everything injected.
as for the transaction stuff… i’ve seen that approach and while i like it, i’m trying not to go overboard with passing Action or Func references so i haven’t gone down that road yet (so far). I’m actually thinking of going with a [IsTransactional] PostSharp attribute to decorate my service methods.
June 24th, 2008 at 10:45 pm
Nice. Do you have a view on how well this approach will integrate with WCF?
I’ve found integrating NH (specifically Session/SessionFactory management), IoC and WCF to be *challenging* to say the least.
At the moment, I’m utilising a [UnitOfWorkContext] attribute to manage the Session, which essentially makes using IoC impossible. I’ll definitely revisit the work I’ve cobbled together so far to look at this approach.
June 24th, 2008 at 10:52 pm
My WCF service methods look like the one that is shown in the post, so they can play along nicely… actually, WCF and NH don’t even know about each other here, because i keep NHibernate contained behind the service layer.
Btw, you could do exactly the same with your UnitOfWorkContext attribute like i do with my using statement. My UnitOfWork class simply creates a session and associates it with the current thread. You could do the exact same thing, only you’d use the IoC container within the attribute code.
June 24th, 2008 at 11:09 pm
Excellent. I’m finally seeing the light at the end of the NH/WCF/IoC integration tunnel.
Essentially, the mechanism I’ve been using for instantiating the SessionFactory is not compatible with IoC, whether I was using WCF or not.
Your approach is much neater.
June 24th, 2008 at 11:12 pm
one thing you have to keep in mind if you do it through the attribute is that you won’t have an easy way to reference the current IUnitOfWork instance, and thus, no easy way to ask it to begin a transaction. So the attribute might not be such a good idea, unless you also provide a [Transactional] attribute but then you have to get the attributes to work together properly which might be a bit tricky.
I was considering going for an attribute based approach as well, but i think i’ll keep the unitofwork/transactional stuff explicitly in the code.
June 25th, 2008 at 10:29 am
I currently have a [UnitOfWorkContext] (automatic transaction) and a [ReadOnlyUnitOfWorkContext] attribute. I stick the UnitOfWorkContext into the OperationContext, so that I have access to the session and transaction from the operation.
I’ll have a play with it, see how both approaches feel.
August 8th, 2008 at 11:36 pm
Hi,
I have some questions regarding your solution / implementation.
- This solution seems to be very usefull in an ASP.NET or Remote Service (WCF, whatever) scenario. However, how do you cope with Rich client applications (Winforms), in where you use NHibernate ? In such a scenario, it is likely to me that you can have multiple sessions opened at a time. (For instance, making use of ‘Long Sessions’. Every form that is opened in your application could have its own Session. How do you cope with that ? Can your ActiveSessionManager cope with that ? It seems that you can have only one session active / open at a time ?
- How do you do the integration with WCF ? I mean, I do understand that your remote service is the only one that knows about NHibernate. The client of your service should indeed be completely ignorant about NHibernate.
But, do you use DTO’s that you sent to your client, or, do you share your business objects that you use in the server with your client as well ? In other words: do you transfer your business objects back and forth from the server to the client and vice versa ?
Or, how does your client knows whether an object has changed , so that you know you have to perform a remote call ? (Or, how does it knows that your object hasn’t changed, so that a remote call is avoided ?).
Also, how do you attach your objects back to your NHibernate session once you’ve transmitted them to your WCF service, making sure that no unnecessary UPDATES are executed ?
August 9th, 2008 at 10:59 am
The ActiveSessionManager is limited to one active session per thread, so no, it’s not very well suited for WinForms development.
as for WCF… i prefer the DTO approach because your client really shouldn’t know about your real entities IMHO. If you try to send your entities accross the service wire then you’re opening up a can of worms which actually makes a lot of things a lot more difficult than they should be.
If you do want to send your entities to the client, then you’ll have to implement your own dirty-tracking within the entities if you want to avoid unnecessary update statements later on when you get back server-side. You’ll also have to use an interceptor (or maybe an event listener in NH2.0) to hook into NHibernate’s dirty checking so you can perform your own custom dirty checks.
Re-attaching of your entities to the serverside session can be done with session.Update(myEntity) if i recall correctly. This entire scenario is generally discouraged though.
Mapping from entities to DTO’s and back again seems like it’s a lot of work, but it’s easy code and it actually avoids a lot of complexity later on
And about avoiding the remote calls if the object hasn’t changed… regardless of whether you’re using entities or DTO’s, you always know which actions the user has (or hasn’t) performed so it’s usually better to use that to decide whether or not to make a remote call instead of depending on a myEntity.IsDirty check or something like that.
August 10th, 2008 at 11:00 am
That’s where I wanted to go
: if you send your business objects to the client, you indeed have to implement your own dirty checking, which is a pity since NHibernate is already taking care of that.
So, indeed, I agree with you that it using DTO’s is maybe the preferred approach, although it initially adds another layer of complexity, and tedious code.
Another thing that I’m thinking off: I can image that you would want some simple logic (validation-logic maybe) to be available at the client as well, so your DTO’s should be more then just simple DTO’s but, you wouldn’t want to duplicate any code as well.
September 13th, 2008 at 8:36 pm
Great example! I am in the middle of a project which uses NHibernate with WCF and I will probably make use of this pattern/solution in my project.
A small note: In DisposeObjects() method of your UnitOfWork class, you don’t need to call both Close() and Dispose() methods on session object, they both do the same thing. Actually there is no harm in this case, because the second call will simply be ignored. The classes that use Disposable pattern generally expose methods like Close() to do the same thing with Dispose(), probably “Close” word is counter to the “Open” which had initialized that object.