These old forums are deprecated now and set to read-only. We are waiting for you on our new forums!
More modern, Discourse-based and with GitHub/Google/Twitter authentication built-in.

All times are UTC - 5 hours [ DST ]



Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 3 posts ] 
Author Message
 Post subject: ObjectDeletedException when manipulating parent-child
PostPosted: Thu Nov 02, 2006 5:32 pm 
Beginner
Beginner

Joined: Thu Nov 02, 2006 5:11 pm
Posts: 32
Location: Toronto
Hi,

I have 2 classes that form a parent-child relationship. I am trying to move all children from one instance of a parent to another parent instance, but I'm getting an ObjectDeletedException. Details below.

Hibernate version: 1.0.2

Mapping documents:

I have a Patient class and a PatientProfile class. The Patient has a set of PatientProfiles, mapped as a parent-child relationship, as shown:

Code:
  <class name="Patient" proxy="Patient" table="Patient_">
    <id name="OID" column="OID_" type="Int64">
      <generator class="hilo">
        <param name="max_lo">100</param>
      </generator>
    </id>
    <version name="Version" column="Version_"/>

    <set name="Profiles" lazy="true" inverse="true" cascade="all-delete-orphan" access="nosetter.camelcase-underscore">
      <key column="PatientOID_"/>
      <one-to-many class="PatientProfile"/>
    </set>
  </class>

  <class name="PatientProfile" proxy="PatientProfile" table="PatientProfile_">
    <id name="OID" column="OID_" type="Int64">
      <generator class="hilo">
        <param name="max_lo">100</param>
      </generator>
    </id>
    <version name="Version" column="Version_"/>

    <many-to-one name="Patient" class="Patient" column="PatientOID_" not-null="true" fetch="join"/>
  </class>



Code between sessionFactory.openSession() and session.close():

The purpose of the code is to move all PatientProfiles from one Patient to another Patient, and delete the patient with no profiles, as shown here:

Code:
using (ITransaction trans = session.BeginTransaction())
{
        Patient a = (Patient)session.Load(typeof(Patient), idA);
        Patient b = (Patient)session.Load(typeof(Patient), idB);

        // copy patient b profiles into temp arraylist
        ArrayList bProfiles = new ArrayList(b.Profiles);

        // Move profiles from patient b to patient a
        foreach (PatientProfile bProfile in bProfiles)
        {
            if (bProfile.Patient != null)
            {
                b.Profiles.Remove(bProfile);
            }
            bProfile.Patient = a;
            a.Profiles.Add(bProfile);
        }
        session.Delete(b);

    trans.Commit();
}


Full stack trace of any exception that occurs:

However, NHibernate seems to think that I have not removed the patient profiles from the original collection, I think, as shown here:


Code:
A first chance exception of type 'NHibernate.ObjectDeletedException' occurred in NHibernate.dll
System.Transactions Critical: 0 : <TraceRecord xmlns="http://schemas.microsoft.com/2004/10/E2ETraceEvent/TraceRecord" Severity="Critical"><TraceIdentifier>http://msdn.microsoft.com/TraceCodes/System/ActivityTracing/2004/07/Reliability/Exception/Unhandled</TraceIdentifier><Description>Unhandled exception</Description><AppDomain>HibernateTest.vshost.exe</AppDomain><Exception><ExceptionType>NHibernate.ObjectDeletedException, NHibernate, Version=1.0.2.0, Culture=neutral, PublicKeyToken=154fdcb44c4484fc</ExceptionType><Message>deleted object would be re-saved by cascade (remove deleted object from associations): 405, of class: HibernateTest.PatientProfile</Message><StackTrace>   at NHibernate.Impl.SessionImpl.ForceFlush(EntityEntry e)
   at NHibernate.Impl.SessionImpl.Save(Object obj)
   at NHibernate.Impl.SessionImpl.SaveOrUpdate(Object obj)
   at NHibernate.Engine.Cascades.CascadingAction.ActionSaveUpdateClass.Cascade(ISessionImplementor session, Object child, Object anything)
   at NHibernate.Engine.Cascades.Cascade(ISessionImplementor session, Object child, IType type, CascadingAction action, CascadeStyle style, CascadePoint cascadeTo, Object anything)
   at NHibernate.Engine.Cascades.CascadeCollection(CascadingAction action, CascadeStyle style, PersistentCollectionType collectionType, IType elemType, Object child, CascadePoint cascadeVia, ISessionImplementor session, Object anything)
   at NHibernate.Engine.Cascades.Cascade(ISessionImplementor session, Object child, IType type, CascadingAction action, CascadeStyle style, CascadePoint cascadeTo, Object anything)
   at NHibernate.Engine.Cascades.Cascade(ISessionImplementor session, IClassPersister persister, Object parent, CascadingAction action, CascadePoint cascadeTo, Object anything)
   at NHibernate.Engine.Cascades.Cascade(ISessionImplementor session, IClassPersister persister, Object parent, CascadingAction action, CascadePoint cascadeTo)
   at NHibernate.Impl.SessionImpl.PreFlushEntities()
   at NHibernate.Impl.SessionImpl.FlushEverything()
   at NHibernate.Impl.SessionImpl.Flush()
   at NHibernate.Transaction.AdoTransaction.Commit()
   at HibernateTest.Program.Main(String[] args) in

Name and version of the database you are using:
SQL Server 2005

The generated SQL (show_sql=true):

no SQL generated yet

Am I doing something incorrectly, or is this a bug?

Thanks,

jr


Top
 Profile  
 
 Post subject:
PostPosted: Fri Nov 03, 2006 2:03 am 
Regular
Regular

Joined: Tue Feb 21, 2006 9:50 am
Posts: 107
i think you don't need to delete the profiles. In database terms you just change the foreign key reference. So a

Code:
session.SaveOrUpdate(a);
session.SaveOrUpdate(b);

instead of

Code:
session.Delete(b);

should be enough.

Regards
Klaus


Top
 Profile  
 
 Post subject:
PostPosted: Fri Nov 03, 2006 1:34 pm 
Beginner
Beginner

Joined: Thu Nov 02, 2006 5:11 pm
Posts: 32
Location: Toronto
Hi Klaus,

Thanks for your suggestion. However, the code that I posted doesn't delete the profiles - it moves them from one patient to another, and then attempts to delete the "childless" patient. This delete is necessary, since I don't want a patient with no children left in the database.

To confuse matters further, even if I were to remove

Code:
session.Delete(b);


from the above code, the behaviour is still not what I would expect. The following SQL statements are issued:

Code:
NHibernate: UPDATE ris4.dbo.Patient_ SET Version_ = @p0 WHERE OID_ = @p1 AND Version_ = @p2
@p0 = '9'
@p1 = '102'
@p2 = '8'
NHibernate: UPDATE ris4.dbo.Patient_ SET Version_ = @p0 WHERE OID_ = @p1 AND Version_ = @p2
@p0 = '1'
@p1 = '304'
@p2 = '0'
NHibernate: DELETE FROM ris4.dbo.PatientProfile_ WHERE OID_ = @p0 AND Version_ = @p1
@p0 = '405'
@p1 = '0'


The first 2 statements simply update the Version of the Patients. The last statement should, as you pointed out, just change the foreign key reference of the PatientProfile, but instead it deletes it.

Also, I don't think it is necessary to explicitly do:

Code:
session.SaveOrUpdate(a);
session.SaveOrUpdate(a);


because those objects are already in the session and should therefore be marked dirty.

So it seems to me that this is either a bug, or my understanding of the workings of NHibernate is totally incorrect.


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 3 posts ] 

All times are UTC - 5 hours [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.