*Current Approach*

In an ASP.NET web forms app (using Spring.NET and NHibernate) we have an 
aggregate root (*Person*) whose details are captured across a number of 
screens/pages. The *Person* entity exists prior to entering into this 
workflow, and all changes made to the *Person* object graph are atomic, and 
so should only be flushed to database upon submission of the final screen.

To achieve this, we load the *Person* (lazily) from the database using 
NHibernate 3.2 the first time into the first page, and thereafter we load 
and save the serialized *Person* object graph to a HTTP Session variable as 
we page through the process.

After retrieving the *Person* out of the HTTP Session, it is in a detached 
state from the current NHibernate session, so we re-attach by invoking the *
Update()* method on the current session, like so:

var sessionPerson = Session[PersonSessionName] as Person;var currentSession = 
SessionFactory.GetCurrentSession();
currentSession.Update(sessionPerson);

Note: Using *Lock()* threw an exception, advising that the “reassociated 
object has dirty collection”.

When reattached, we can traverse through the object graph as expected, 
pulling data from the database for child entities which had not yet been 
loaded into memory.

*Subset of Mapping Files*

<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" auto-import="false" 
assembly="Domain" namespace=" TestApp.Domain">
  <class name="Person" table="Person">
    <id name="Id">
      <generator class="TestApp.CustomNHibernateHiLoGenerator, TestApp.Core" />
    </id>
    <property name="Name" not-null="false" />

    <bag name="PersonCountries" access="field.camelcase-underscore" 
cascade="all-delete-orphan">
      <key column="PersonId" foreign-key="FK_ PersonCountry_Person" 
not-null="true" />
      <one-to-many class="PersonCountry" />
    </bag>
  </class>

  <class name="Country" table="Country">
    <id name="Id">
      <generator class="TestApp.CustomNHibernateHiLoGenerator, TestApp.Core" />
    </id>
    ... No back reference to Person
  </class></hibernate-mapping>

*Domain*

public class PersonCountry : Entity, ICloneable{
    // No properties of note}
public class Person : Entity, ICloneable{
    public virtual string Name { get; set; }
    public virtual IEnumerable<PersonCountry> PersonCountries { get; set; }
    ... 
    // More Properties}

*Flushing changes to database*

.. // Code-behindPricingService.Save(ProductContext.Pricing, forceMerge: true); 
           

public class PricingService : IPricingService{
   [Transaction]  // Spring.NET transaction
   public Pricing Save(Pricing pricing, bool forceMerge = false)
   {            
      if(forceMerge)
      {
         CurrentSession.Merge(entity);
      }
      else
      {
         CurrentSession.SaveOrUpdate(entity);
      }
   }}

When it comes time to flush all changes to the database, provided we only 
change *Name*, the change works as expected. However, adding a new *Country* 
item 
to *Person* causes the cascading of the *Merge()* on one-to-many 
relationships to fail with the following exception (oddly, removing a *
Country* works fine).

NHibernate.StaleStateException: Batch update returned unexpected row count from 
update; actual row count: 0; Expected: 1

Any help would be greatly appreciated.

Reply via email to