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,026 | Comments: 44,842

filter by tags archive

NHibernate – Cross session operations

time to read 5 min | 816 words

This started out as a support question, but it is an interesting enough (and general enough) that I think it is important to make sure that it is recorded.

When working with detached entities (from another session), sometimes, at seemingly random places, NHibernate will throw a NonUniqueObjectException. Where it actually happen and the exact cause depend on several variables, but the root problem is simple: working with detached entities safely requires that you be aware of possible identity map violations.

Let us look at some code and then I can explain:

using (var session = sessionFactory.OpenSession())
using (var tx = session.BeginTransaction())
// get the entity
post = session.Get<Post>(postId);
// force the association to be eagerly loaded

using (var session = sessionFactory.OpenSession())
using (var tx = session.BeginTransaction())
// get the user for the entity
var anotherUser = session.Get<User>(post.User.Id);

// will return false
ReferenceEquals(anotherUser, post.User);

// opps, user instance with the same id but with different
// reference was detected


The reason that the problem seems obscure at first is that there are quite a few variables that are going to affect how this will behave. In order to reproduce the issue you need:

  • An association that is marked with a cascade option, such as “save-update”, “all” or “all-delete-orphan”
  • The entity this association points needs to be loaded in the second session.

Depending on what you are doing (saving an entity vs. updating it) and what the options are for the id generation, you may get the error on the SaveOrUpdate or on the Commit.

The actual details are pretty unimportant, but understanding what is going on is. The issue is that NHibernate has been asked to perform something that violate one of its core assumptions, break the identity map.

Because of the cascade options set on Post.User, we are asking NHibernate to also save the User instance associated with the post. The problem is that when NHibernate is encountering that, it is going to see an entity with an id that is already on the session but as a different reference. That violates the identity map rules and force NHibernate to throw an exception.

The root cause is, as I mentioned, trying to work with a detached entity as if it was a regular entity. NHibernate provides a different API for working with detached entities safely, precisely because of those sort of reasons.

The appropriate way of handling such an issue is to use the Merge method, which will take a detached object graph and merge it into the session, properly resolving such conflict. Note, however, that Merge will return a different entity instance than the one that you passed.

Let us look at the code:

using (var session = sessionFactory.OpenSession())
using (var tx = session.BeginTransaction())
// get the user for the entity
var anotherUser = session.Get<User>(post.User.Id);

// will return false
ReferenceEquals(anotherUser, post.User);

// will merge the detached entity into the session
// creating NEW entity instance or re-using the one
// that is already in the session
var mergedPost = (Post)session.Merge(post);

// will return false
ReferenceEquals(mergedPost, post);

// will return true
ReferenceEquals(anotherUser, mergedPost.User);


As you can see, this is a fairly small change, and NHibernate now takes care of wiring up everything correctly even in the face of conflicting changes.

You can play around with the code here:




Steve Bohlen

This is a great post about a thorny recurring issue that can (sometimes) be hard to explain to people; now I have an easy reference article to point people to when they run up against this!

Scott White

I use Google Reader extensively. I found your site no problem. I wouldn't worry about it.


NHibernateUtil.Initialize() is a much better way to eager initialize

D Kulkarni

Any chance of getting a rev of LINQ for nhibernate for the 2.1.1 GA? I am getting a bunch of assembly version mismatch errors.




is this (merging a detatched entity into a session) the only intended aspect of merge? or are there others as well?


What is the downside of using session.Lock(item, LockMode.None) for associating item with session?

I ask because I have the folowing scenario:

I have to delete a few trees of items,when each item may belong to more then one tree. Merging each item into session means I will have to traverse all the trees and replace all instances of old item with new item. Will the session.Lock have unintended side effects?


Thanks Oren. You made my day, I owe you a beer! :)


hi, I want to know how to implement session per view in multilayer project.

could you show us same sample?

Ayende Rahien


Search the blog, and read about rhino commons.

Comment preview

Comments have been closed on this topic.


No future posts left, oh my!


  1. Technical observations from my wife (3):
    13 Nov 2015 - Production issues
  2. Production postmortem (13):
    13 Nov 2015 - The case of the “it is slow on that machine (only)”
  3. Speaking (5):
    09 Nov 2015 - Community talk in Kiev, Ukraine–What does it take to be a good developer
  4. Find the bug (5):
    11 Sep 2015 - The concurrent memory buster
  5. Buffer allocation strategies (3):
    09 Sep 2015 - Bad usage patterns
View all series


Main feed Feed Stats
Comments feed   Comments Feed Stats