NHibernate
NHibernate's Session is implicitly a unit of work. In a typical web application, you put the ISession in ASP.Net Session, in one of two patterns:
- Open session per view (open session in Application_BeginRequest, close -and save to database - in Application_EndRequest).
- Session per conversation (a business transaction spanning multiple postbacks)
If you register the BeginRequest event to open the session, you can check for HttpContext and the Handler (DefaultHttpHandler won't require a session)- but generally the impact of opening a session is trivial if the page doesn't access the database.
Note: When there is a database error, sessions must be discarded and cannot be reused. If you don't dispose in EndRequest, and you need to do other database work, open a new NHibernate Session.
This is a very simple IDisposable Unit of Work, designed for testing. It opens a session and transaction, and disposes of it afterwards. Note that if a session is already open, it continues using it.
A more elaborate version incorporating what's in my SessionManager is this Unit Of Work.
using System;
using System.Data;
using NHibernate;
using Northwind.Repositories;
namespace Northwind
{
/// <summary>
/// A simple Unit of Work wrapper. It is IDisposable. Call <see cref="Commit"/> or call <see cref="Rollback"/> to abort the transaction.
/// </summary>
public sealed class UnitOfWork : IDisposable
{
private readonly ISession session;
private ITransaction transaction;
public UnitOfWork()
{
session = SessionManager.Instance.Session; //this may be an already open session...
session.FlushMode = FlushMode.Auto; //default
transaction = session.BeginTransaction(IsolationLevel.ReadCommitted);
}
public ISession Current
{
get { return session; }
}
/// <summary>
/// Commits this instance.
/// </summary>
public void Commit()
{
//becuase flushMode is auto, this will automatically commit when disposed
if (!transaction.IsActive)
throw new InvalidOperationException("No active transaction");
transaction.Commit();
//start a new transaction
transaction = session.BeginTransaction(IsolationLevel.ReadCommitted);
}
/// <summary>
/// Rolls back this instance. You should probably close session.
/// </summary>
public void Rollback()
{
if (transaction.IsActive) transaction.Rollback();
}
#region IDisposable Members
public void Dispose()
{
if (session != null) session.Close();
}
#endregion
}
}