This issue was why I created a simple UnitOfWork that combines ISession and ITransaction.
In tests, I would write the following code:
var product = new Product {Name = "Apple", Category = "Fruits"};
using (var session = _sessionFactory.OpenSession())
using (var transaction = _session.BeginTransaction())
{
session.Save(product);
transaction.Commit();
}
when I really wanted:
var product = new Product {Name = "Apple", Category = "Fruits"};
using (var unitOfWork = new UnitOfWork(_sessionFactory))
{
unitOfWork.CurrentSession.Save(product);
unitOfWork.Commit();
}
Here is my unit of work implementation,
using NHibernate;
namespace NHibernateBootstrap.Core.Persistence
{
public class UnitOfWork : IUnitOfWork
{
private readonly ISessionFactory _sessionFactory;
private readonly ITransaction _transaction;
public UnitOfWork(ISessionFactory sessionFactory)
{
_sessionFactory = sessionFactory;
CurrentSession = _sessionFactory.OpenSession();
_transaction = CurrentSession.BeginTransaction();
}
public ISession CurrentSession { get; private set;}
public void Dispose()
{
CurrentSession.Close();
CurrentSession = null;
}
public void Commit()
{
_transaction.Commit();
}
}
}
As far as the when to call Commit() (either using ITransaction or UnitOfWork), I believe that it should be done explicitly before the end of your request. If you don't call it, then the UnitOfWork should clean itself up, but not commit. Alternatively, you could use an HttpModule to commit in an EndRequest handler.
I think this is easily handled by using a ViewModel class. Lets say you have an OrderView in your app, which displays an order. On this view you have a dropdown "Item Type", containing a list of item types.
The model that should be fed to your view should be a class like OrderViewModel which contains a list of ItemType objects. When the controller loads the list of ItemType objects from the DB using NHib, it can then insert extra "special" Item Types into the collection, such as one for "--SELECT--".
In other words, don't bind directly to an Nhibernate collection mapping property -- use Nhibernate to load data into a list which you can then manipulate at will.
Best Solution
So, I apologize that we did not get the NHibernate with StructureMap example done earlier. Eventually, I would like to publish it in the StructureMap documentation, but I need some feedback first. You can see the full example on my blog:
http://trason.net/journal/2009/10/7/bootstrapping-nhibernate-with-structuremap.html
That being said, I can hit the highlights here. There is an NHibernateRegistry that makes available four things: an NHibernate.Configuration (as a Singleton), an ISessionFactory (as a Singleton), an ISession (scoped Hybrid (HttpContext if available, falling back to Thread local storage)), and a very simple IUnitOfWork. Also, there is an HttpModule to manage the UnitOfWork per web request.
Here is the code for the NHibernateRegistry:
Here is the code for the Unit of Work:
Here is the NHibernateModule for web applications: