Ayende @ Rahien

My name is Oren Eini
Founder of Hibernating Rhinos LTD and RavenDB.
You can reach me by phone or email:


+972 52-548-6969

, @ Q c

Posts: 6,128 | Comments: 45,551

filter by tags archive

Nhibernate Unit of Work & multiple reuqests

time to read 2 min | 284 words

Another post request from the forum:


I'd love to get some detail on how to make the most of NHibernate's unit of work capability in a web app scenario.

It seems like in a web app, because your unit of work may be split across multiple web requests (and therefore sessions), it's hard to use NHibernate's change tracking etc effectively and I find myself doing unit of work tracking myself.

This seems to lead inevitably to an anaemic domain model and feels like fighting the tool.

Well, I am going to take that in two parts. First, having a unit of work that span requests is something that is possible (and I’ll discuss how to implement shortly), but I don’t recommend it. It is much easier to build your application so each request is a single unit of work.

Now, about actually implement a request that spans multiple requests, it is not really hard. It is called long conversation, or session per business transaction. Here is a detailed explanation on how NHibernate Burrow is achieving this.

But basically, it is quite simple. You set the session’s flush mode to Never, and you store NHibernate’s session in the ASP.Net session. Now, for each request, you can get the NHibernate session for the ASP.Net session and continue working with the same session and entities, taking advantage of change tracking, transparent persistence and all the other features that make NHibernate easy.

There are several frameworks out there that would handle this for you, Burrow, as I mentioned and Rhino Commons as well.



Hi, having such feature is very convenient. In the company I'm working for we are using 'Sooda' ORM and it's capable of serializing and deserializing transaction state. Using this we can implement long living 'transactions' that span multiple http requests. Transaction state is serialized to xml files, so even in case of application restart users will not lose their uncommited data and can continue working as if nothing happened. BTW by transaction state I mean the state of all objects inserted or modified in single ORM session. I havent yet tried to do the same with NHibernate, but hope it's possible.

Rik Hemsley

"It is much easier to build your application so each request is a single unit of work."

When a user is 'building' a possibly-temporary entity from the (web) UI, they may cause dozens of requests when moving between pages and with AJAX.

I'm interested to know how you (Oren) handle this common situation without a unit of work which spans HTTP requests.

Kelly Stuard

I'm curious how you have the UOW span multiple requests when you are in a multi-server webfarm. Does nHib session work ok when de-/re-serialized through the out-of-proc session state providers?

Neil Barnwell

You suggest putting the NHibernate session in the ASP.NET session, but is that really a good idea? What if you are load balancing the web servers? What if you are using SQL Session Persistence?


Also, using the ASP.NET session doesn't scale.

Kelly Stuard

On a side note: the "future posts" section gives me something to look forward to. For instance, the "8 days: Help requests that make me want to cry" sounds like a good one.


but is that really a good idea?

From my point of view, I hate aspnet session, now I avoid these like plague, it's not yet to the point of viewstate and dataset but I feel it'll be soon reaching that point...

Unfortunnatly, at work I've seen SqlTransaction objects being serialized inside asp.net session inside web services... :(

Happily that I don't have to look much into the code of these WS...

Tyler Burd

For requests that span multiple pages I generally don't write the data to the actual entity until the very last screen is submitted. I keep track of the previous pages' data via hidden form fields. OR, I create a separate persistent model solely to save the user's progress. When the last screen is complete I then copy that "form" entity's data into the "business" entity.

This does seem like more work at the outset, but it's a hell of a lot easier than managing a long conversation by dropping the NH session into the ASP session and all of the problems with concurrency that creates.

Fabio Maulo


Exactly what I mean with "WEB app should have it in mind".


Question: how does the session per request deal with this very common scenario: a user retrieve the data for viewing in the first request and edits and submit his changes in a second request.

You can argue to re-attach the entity on the second request but you will lose all the tracking information.


Right now, I am searching for the holy pattern to span a session through multiple requests. One approach could be to record every request, that modifies the entity, and before each request, just replay (re-apply) them on the entity. This would work for very simple scenarios, but often, the commands take effect on a whole aggregate, not just a standalone entity.

So now, the session-per-conversation pattern seems to be the most viable solution for me, with all of it's limitations. Until you suggest me a better one...

Ayende Rahien


If that is the case, then you need to make sure that your entities are serializable. The session itself is.

Theoretically, you can serialize it back & forth between servers.

In practice, I would feel much better if you used sticky sessions, though.

Ayende Rahien

Rafal & Kelly,

Yes, NH support serialization of the session.


Wait for it, really wait for it.


SqlTransaction inside ASP.Net Sessions.

You make me want to cry again.


You use versioning, and just update the instance. NH takes care of everything else.


It seems like if you can't use session per conversation, you can just keep the state on the client, no need to do applications of diffs.


I'm with you Tyler. Keep it simple. My head hurts from all the mental gymnastics being discussed.



can you explain more? how does NH know if the entity has changed? does it fetch from the db and compare record by record and update if something has changed? are you suggesting to increment the version number manually? isn't the version number number manipulated internally by NH?

please explain more. Thanks.

Ayende Rahien


No need to do anything else, just materialize the values from the client (including the version number that the user editted) and call Update on it.

That would cause NH to update the row, and we use the version number to ensure concurrency control



What if the user didn't change anything will the row still be updated?

Ayende Rahien


If so, to its original values, with is a no op anyway, so you wouldn't care.



But it will still increment the version number, right?

The reason I asked this is that if I wrap the 2 requests in a conversation and keep the original NH session in ASP.NET session, then if the use makes no changes to the entity NH will not update it.

so it's kind of we have to use conversations anyway because they're very common just like in this scenario and the session-per-request pattern is not sufficient in most cases.

Please correct me if I'm wrong.

Ayende Rahien


Yes, it probably will.

If you care about that, take a look at Merge



You mentioned avoiding session state. Just wondering how you usually implement long conversations without using session state?

Comment preview

Comments have been closed on this topic.


  1. The worker pattern - 4 hours from now

There are posts all the way to May 30, 2016


  1. The design of RavenDB 4.0 (14):
    26 May 2016 - The client side
  2. RavenDB 3.5 whirl wind tour (14):
    25 May 2016 - Got anything to declare, ya smuggler?
  3. Tasks for the new comer (2):
    15 Apr 2016 - Quartz.NET with RavenDB
  4. Code through the looking glass (5):
    18 Mar 2016 - And a linear search to rule them
  5. Find the bug (8):
    29 Feb 2016 - When you can't rely on your own identity
View all series


Main feed Feed Stats
Comments feed   Comments Feed Stats