title: How does one gracefully merge object graphs after NHibernate StaleObjectStateException?
body: <p>We are trying to combine objects after a StaleObjectStateException has been thrown to save a merged copy.</p>
  
  <p>Here's our environmental situation:</p>
  
  <ul>
  <li>List item</li>
  <li>Multi-user system</li>
  <li>WPF Desktop application, SQL Server 2008 database</li>
  <li>NHibernate 3.1.0.4000, FluentNHibernate 1.2.0.712</li>
  <li>Global, long-running NHibernate sessions [for the moment. We understand session-per-presenter is the recommended pattern, but do not have time in our project schedule to convert at present.]</li>
  <li>Top-down saves and property navigation (that is to say we save the top-level object (herein called Parent) in our domain graph) </li>
  <li>.Cascade.AllDeleteOrphan() used in most cases.</li>
  <li>Users exclusively own some objects in the domain graph, but share ownership of the Parent.</li>
  <li>Navigation properties on Children objects do not exist.</li>
  <li>All classes have numeric ID and numeric Version fields.</li>
  </ul>
  
  <p>Use case:</p>
  
  <ul>
  <li>User 1 starts application and opens Parent.</li>
  <li>User 2 starts application and opens Parent.</li>
  <li>User 2 adds a child (herein C2).</li>
  <li>User 2 saves Parent.</li>
  <li>User 1 adds a child (herein C1).</li>
  <li>User 1 saves Parent.</li>
  <li>User 1 receives a StaleObjectStateException (and rightly so)</li>
  </ul>
  
  <p>We want to <em>gracefully</em> handle the exception. 
  Because the users share ownership of the parent, User 1 should be able to save successfully, and save the Parent with both his new child, and User 2's child.</p>
  
  <p>When SOSE is thrown, according to Ayende (<a href="http://msdn.microsoft.com/en-us/magazine/ee819139.aspx" rel="nofollow noreferrer">http://msdn.microsoft.com/en-us/magazine/ee819139.aspx</a>):</p>
  
  <blockquote>
    <p>your session and its loaded entities are toast, because with NHibernate, an exception thrown 
    from a session moves that session into an undefined state. You can no longer use that session
    or any loaded entities</p>
  </blockquote>
  
  <p>C1 has already been assigned an ID and Version # by the now-not-useful session. (I wish it had not been.)</p>
  
  <p>How do we combine the use of ISession.Merge() and ISession.Refresh() to get a newly saved Parent that has both C1 and C2 ?</p>
  
  <p>We have tried a number of arcane permutations, none of which fully work.
  Usually, either a "row was updated or deleted by another transaction (or unsaved-value mapping was incorrect" or an actual ID collision at the ODBC level.</p>
  
  <p>Our theory, at the moment:</p>
  
  <ol>
  <li>Reset version numbers on C1 (to prevent "unsaved-value mapping was incorrect")</li>
  <li>Get a new session</li>
  <li>newSession.Refresh(C1);</li>
  <li>newParent = newSession.QueryOver[...]</li>
  <li>newParent.Add(C1);</li>
  <li>newSession.SaveOrUpdate(newParent)</li>
  </ol>
  
  <p>However, all the documentation suggests that newSession.Merge is <em>supposed</em> to be sufficient.</p>
  
  <p>Other posts used as research:
  <BR/><a href="https://stackoverflow.com/questions/5611830/fluent-nhibernate-newbie-row-was-updated-or-deleted-by-another-transaction">Fluent NHibernate Newbie: Row was updated or deleted by another transaction</a>
  <BR/><a href="https://stackoverflow.com/questions/6845815/is-there-an-alternative-to-isession-merge-that-doesnt-throw-when-using-optimi">Is there an alternative to ISession.Merge() that doesn&#39;t throw when using optimistic locking?</a>
  <BR/><a href="https://stackoverflow.com/questions/3158491/staleobjectstateexception-row-was-updated-or-deleted-by">StaleObjectstateException row was updated or deleted by</a>
  <BR/><a href="https://stackoverflow.com/questions/6268249/how-i-can-tell-nhibernate-to-save-only-changed-properties">How I can tell NHibernate to save only changed properties</a>
  <BR/><a href="https://stackoverflow.com/questions/4838786/hibernate-jpa-how-to-handle-staleobjectstateexception-when-several-object-has">Hibernate (JPA): how to handle StaleObjectStateException when several object has been modified and commited</a> (java, but relevant, i think)</p>