NHibernate supports async
NHibernate, the O/R-mapper that some people consider as dead, is actually alive and very much alive. The release of version 5.0 at last autumn was somehow quiet and didn’t got much attention. But there is something that brings NHibernate to modern era – support for asynchronous database access. This blog post gives brief overview of new async methods in NHibernate and shares some ideas about how to start using them.
Why NHibernate?
Although NHibernate seemed (almost) dead for long time it is back in active development. Those who started using it years ago don’t easily want to go with alternatives when building enterprise grade applications. It has longer learning curve than Entity Framework but it pays off later as tweaking and extending is easier and we have better control over generated SQL (take a look at show-case of Entity Framework horrors – i saw same kind of madness also with Entity Framework 6). If it is about application that can be demanding on database and ORM layer I will still go with NHibernate.
New async methods
Let’s go with some examples I took from one real code base that is moving to asynchronous NHibernate.
ListAsync() method can be used with ICriteria to get results asynchronously. There is also UniqueResultAsync() method available.
public async Task<IList<ProductGroup>> ListAll()
{
var criteria = Session.CreateCriteria<ProductGroup>();
criteria.AddOrder(Order.Asc("Name"));
return await criteria.ListAsync<ProductGroup>();
}
Here are samples of some asynchronous methods of ISession. The fragment of code is taken from class that hides implementation details of ORM from consuming application. Take it as an implementation class that follows general data access interface in system that is injected to classes using dependency injection.
public async Task Rollback(object transaction)
{
var trans = transaction as ITransaction;
await trans.RollbackAsync();
trans.Dispose();
}
public async Task Commit(object transaction)
{
var trans = transaction as ITransaction;
await trans.CommitAsync();
trans.Dispose();
}
public async Task Delete(object entity)
{
await GetCurrentSession().DeleteAsync(entity);
}
public async Task Save(object entity)
{
await GetCurrentSession().SaveOrUpdateAsync(entity);
}
public async Task<T> Get<T>(object id)
{
return await GetCurrentSession().GetAsync<T>(id);
}
ISession has many other new asynchronous methods like EvictAsync(), FlushAsync(), IsDirtyAsync(), LoadAsync() to name a few.
There are also new async methods for Query API: FirstOrDefaultAsync(), AllAsync(), MaxAsync() and many others. The parts of DAL that use Query API can also be made asynchronous now.
Moving to async HNibernate
Those who plan to use asynchronous part of NHibernate can consider two paths to start using it:
- Replace synchronous calls with async ones – it leaves no way to switch between synchronous and async calls in consuming applications. If something goes wrong then switching back to synchronous calls means a lot of work.
- Add async calls to DAL – adding new set of calls gives option to move to async calls step by step and move back to synchronous calls if there are issues with async ones.
Like always, it depends on many things.
Wrapping up
It’s good to see that NHibernate is alive again and makes progress. New async methods for data access bring NHibernate to modern era. It takes some planning and analyzes to make the move in stable enterprise applications but it is time to start investigating those new features already today.
Hi, Gunnar! Good article. The only problem is, unlike other async implementations, NHibernate’s ISession is still single-threaded, so it may cause other problems.
Hi!
It doesn’t cause problems actually. Database context in EF doesn’t support multi-threading too. You need instance of mapper per thread. If I missed something then please explain more :)
Please have a look at, for example: http://enterprisecraftsmanship.com/2017/12/11/nhibernate-async-support/.
“Note that this feature is not intended for parallelism”
Yes, that’s correct because underlying System.Data connection classes doesn’t support it.If it’s about threading then every thread has it’s own ISession and if data must be shared then it’s possible to use second level cache in NHibernate.