title: NHibernate cascade="all-delete-orphan" is deleting non-orphaned rows
body: <p>When using cascade="all-delete-orphan" NHibernate is deleting a child row that is not orphaned - it has simply been moved to a new parent.</p>
  
  <pre><code>using (var session = sessionFactory.OpenSession())
  {
      using (var transaction = session.BeginTransaction())
      {
          // Get the store we're moving him to 
          Store newStore = session.QueryOver&lt;Store&gt;().Where(...).SingleOrDefault();
  
          // Get existing employee 
          Employee jack = session.QueryOver&lt;Employee&gt;().Where(...).SingleOrDefault();
  
          // Do the move
          jack.Store.Staff.Remove(jack);
          jack.Store = newStore;
          jack.Store.Staff.Add(jack);
  
          transaction.Commit(); 
      }
  }
  </code></pre>
  
  <p>When the commit occurs, a single DELETE statement is generated to delete 'jack' from the database. This behavior would make sense if 'jack' had, in fact, been orphaned but he should now be happily assigned to his new store.</p>
  
  <p>If I change the cascade to "all", the expected UPDATE statement is generated and 'jack' is happily reassigned as expected. However, this causes genuine orphaned rows to remain in the database which is not acceptable.</p>
  
  <p><strong>Is this a bug or is there something I am doing wrong?</strong></p>
  
  <p>Here are the classes:</p>
  
  <pre><code>public class Store
  {
      public virtual Guid Id { get; private set; }
      public virtual string Name { get; set; }
      public virtual IList&lt;Employee&gt; Staff { get; set; }
  }
  
  public class Employee
  {
      public virtual Guid Id { get; private set; }
      public virtual string FirstName { get; set; }
      public virtual string LastName { get; set; }
      public virtual Store Store { get; set; }
  }
  </code></pre>
  
  <p>and the FluentNHibernate mappings:</p>
  
  <pre><code>public class EmployeeMap : ClassMap&lt;Employee&gt;
  {
      public EmployeeMap()
      {
          Id(x =&gt; x.Id).GeneratedBy.Guid();
          Map(x =&gt; x.FirstName);
          Map(x =&gt; x.LastName);
          References(x =&gt; x.Store);
      }
  }
  
  public class StoreMap : ClassMap&lt;Store&gt;
  {
      public StoreMap()
      {
          Id(x =&gt; x.Id).GeneratedBy.Guid();
          Map(x =&gt; x.Name);
          HasMany(x =&gt; x.Staff)
            .Inverse()
            .Cascade.AllDeleteOrphan();
      }
  }
  </code></pre>
  
  <p><strong>UPDATE</strong></p>
  
  <p>After some more testing on this it does seem to be a bug, in that the order of loading the objects alters the outcomes (note the Move Employee is done as above in both cases):</p>
  
  <p>1) Load Store B, Load Store A, Find Employee in A.Staff, Move Employee to B
  ==> <strong>Employee is deleted</strong> (No exception is thrown, Employee is not reinserted)</p>
  
  <p>2) Load Store A, Load Store B, Find Employee in A.Staff, Move Employee to B
  ==> <strong>ObjectDeletedException</strong> (deleted object would be re-saved by cascade (remove deleted object from associations))</p>
  
  <p>The second case appears to be the scenario referred to by @Cole W and discussed <a href="https://stackoverflow.com/questions/6141080/fluent-nhibernate-exception-moving-objects-between-collections/7013522#7013522">here</a> and <a href="http://fabiomaulo.blogspot.com/2009/09/nhibernate-tree-re-parenting.html" rel="nofollow noreferrer">here</a> and a known limitation of orphan handling in NHibernate.</p>
  
  <p>However, the first case appears to be a bug. In my understanding there should not be a scenario where the order in which objects are loaded alters the database changes made by NHibernate. It appears to be a bug that potentially causes data loss.</p>
  
  <p><strong>UPDATE 2</strong></p>
  
  <p>Given the inconsistent behavior that is dependent on load order and the potential for data loss I have logged this as a <a href="https://nhibernate.jira.com/browse/NH-2922" rel="nofollow noreferrer">bug in NHibernate JIRA</a>. The bug report has full code and mappings to demonstrate the problem.</p>