Reputation: 491
I'm getting stuck into NHibernate at the moment and I'm trying to work out how best to correctly design my Repositories whilst correctly managing the lifetime of the Session.
From the examples I've seen, it seems common practise to inject an ISession into each of the repositories as follows:
public class SomeRepository : IRepository
{
private readonly ISession _session;
public SomeRepository(ISession session)
{
_session = session;
}
public IList<T> LoadSomeData()
{
return _session.Query<T>().Where(...).ToList();
}
}
So this is fine, but I can see a couple of cases where there will be problems:
1) There may not be 1 Session for the lifetime of the app.
2) When accessing NHibernate we should always wrap our calls in a Transaction - if the transaction faults then we must Rollback the transaction and close the Session.
In both these cases the Repository would be defunct as it references a closed Session.
My particular application is a long running process, which will only occasionally call into NHibernate, so I would expect a high turnover Sessions instead of keeping 1 Session open for the lifetime of the app.
I am therefore wondering what the established pattern for dealing with this particular situation? I see several potential solutions, but it's hard to see which is the best practise:
1) Rebuild the repositories (and create a new Session) every time the process needs to do some DB work.
2) Inject the Repositories with a SessionFactory. The Repository then exposes this SessionFactory. The consumer of each repository then Opens a new Session at the same time as starting a transaction.
3) Create a UnitOfWork class which is injected into the Repositories and is responsible for managing Session lifetimes & Transactions. Each time a call into a Repository is made, is calls into UnitOfWork, which creates a brand new Session and the call is executed within a Transaction. The repositories therefore have no knowledge of the Sessions/Transactions.
To me, 3) seems like the best solution, and I've seen a few examples of this online, but in all of the examples they only create 1 session within UnitOfWork, and they don't recreate it if the transaction is rolled back.
In addition, a limitation with 3) is that the UnitOfWork is tied to a particular repository, and so you couldn't have a transaction which made calls into different Repositories.
Hope that makes sense and would appreciate any guidance.
Thanks
Upvotes: 0
Views: 2176
Reputation: 96
Actually Session in NHibernate can be used as UnitOfWork. But if you want to use this pattern, here's the implementation: http://nhibernate.info/doc/patternsandpractices/nhibernate-and-the-unit-of-work-pattern.html.
But however the best solution in your list is 1. So you need to create session and repositories every time you need to make a job with DB.
Using the UnitOfWork it will looks like:
using(var uow = new UnitOfWork())
{
var rep1 = new SomeRepository1(uow);
rep1.DoSomeJob();
var rep2 = new SomeRepository2(uow);
rep2.DoSomeOtherJob();
}
Using the native ISession:
using(var session = SessionFactory.OpenSession())
using(var tr = session.BeginTransaction())
{
var rep1 = new SomeRepository1(session);
rep1.DoSomeJob();
var rep2 = new SomeRepository2(session);
rep2.DoSomeOtherJob();
tr.Commit();
}
Also you can use the power of DI/IoC containers to manage sessions lifetime.
If you interested in last option I can show you an example to.
Upvotes: 1