-->
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.  [ 5 posts ] 
Author Message
 Post subject: Many-to-Many cascaded updates behaving very strangely
PostPosted: Thu Jul 09, 2009 8:42 am 
Newbie

Joined: Thu Jul 09, 2009 6:26 am
Posts: 3
We are having a probem with modificaction of detail data in a many-to-many master-detail mapping.

We have a class Entity, with a set of contact numbers associated using a mapping table, so we have Entity, TelephoneNumber and EntityTelephoneNumber tables.

When we create an entity and add numbers to the set and call persist all is 100% and we think it is working just nicely.

The problem comes when updating the number. We load the data from the database using load on the session, then we update the number property of the telephone number and call saveorupdate on the entity. (I know we can load the number alone and call saveorupdate on that, yes it will work, but I cannot write code to traverse the object graph and call update on every property, this is supposed to work, not?)

We are expecting Hibernate to generate SQL that will update the number, which is does. Splendid, but right at the end it generates a statement "delete from EntityTelephoneNumber where TelephoneNumberId = 234" or something like that. This just makes no sense at all.

Looking at the entity all seems 100%, it has a ISet<TelephoneNumber> which has the number in there, the number and Entity have correct Id's and all the object data seems 100%. So why would Hibernate decide to delete the link table entry, thus leaving the TelephoneNumber record orphaned?

We are using NHibernate V2.0.1.4000.

The actual scenario has a little more complexity with the specializations of the Entity class and lots of other properties, but to give the idea this is more or less what the mappings look like if reduced to the problem area:

<class table="Entity"
abstract="true"
name="test.entity"
lazy="false"
polymorphism="explicit"
discriminator-value="0">

<id name="Id" column="EntityId" type="Int32" unsaved-value="0">
<generator class="identity">
</id>

<set name="TelephoneNumbers" table="EntityTelephoneNumbers" cascade="all" lazy="false">
<key>
<column name="EntityId" not-null="true"/>
</key>
</set>

The mapping for Telephone Numbers is basically:

<class name="TelephoneNumbers" table="TelephoneNumbers" lazy="false">
<id name="Id" column="TelephoneNumberId" type="Int32" unsaved-value="0">
<generator class="identity">
</id>

<property name="Number" type="string">
</class>


Top
 Profile  
 
 Post subject: Re: Many-to-Many cascaded updates behaving very strangely
PostPosted: Tue Jul 14, 2009 9:59 am 
Newbie

Joined: Thu Jul 09, 2009 6:26 am
Posts: 3
Ok, I think we got to the bottom of this one, but it still looks like something is wrong in the implementation of NHibernate.

Looking at the implementation I realised that when the update is done the set of phone numbers is cleared out and then the required numbers are added into the list. Seems straightforward, but the new numbers that are added in are created as new objects with the Id of the object set, but because it is being updated we are not calling Load on the objects.

Seems like we are ending up with multiple objects in memory representing the same entity, and that although the update code correctly updates the entity in the database (as the id is != not-saved-value), the engine seems to think that there is no association with the object anymore and removes the link.

So we basically have:

8<---8<---8<---8<---

Person.TelephoneNumbers.Clear();
TelehoneNumber newNumber = new TelephoneNumber();
newNumber.Id = 123; // Getting the value from the front-end
newNumber.Number = "123456"

Person.TelephoneNumbers.Add(newNumber);

Person.SaveOrUpdate();

8<---8<---8<---8<---

This looses the link. But if we do the following it works fine:

8<---8<---8<---8<---
Person.TelephoneNumbers.Clear();
TelehoneNumber newNumber = new TelephoneNumber;
newNumber.Id = 123; // Getting the value from the front-end

newNumber.Load(); // <----- Add this line to make it work !!!

newNumber.Number = "123456"

Person.TelephoneNumbers.Add(newNumber);

Person.SaveOrUpdate();

8<---8<---8<---

Seems like this scenario should either save correctly or throw some exception about concurrent transient objects or something, but not return success and quietly remove the links ...


Top
 Profile  
 
 Post subject: Re: Many-to-Many cascaded updates behaving very strangely
PostPosted: Wed Jul 15, 2009 6:45 am 
Expert
Expert

Joined: Thu Dec 14, 2006 5:57 am
Posts: 1185
Location: Zurich, Switzerland
Does loading and updating happen in the same session ? In that case most likely you need to overwrite Equals() and GetHashCode(). Have a look here:

http://nhforge.org/blogs/nhibernate/archive/2008/09/06/identity-field-equality-and-hash-code.aspx

_________________
--Wolfgang


Top
 Profile  
 
 Post subject: Re: Many-to-Many cascaded updates behaving very strangely
PostPosted: Wed Jul 15, 2009 7:49 am 
Newbie

Joined: Thu Jul 09, 2009 6:26 am
Posts: 3
It is done from a different session. (Assuming that Configuration().Configure().BuildSessionFactory() will always return a new session every time it is called).

In any case, we have implemented both and they seem to work fine. (we implemented a DomainObject base class, I had to strip down the post to bare bones in order to keep it short, sorry if that put you on the wrong track.

Our Equals method checks for a reference match, then checks for equality of Id and returns true if either of these are matched. It then compares the hashcode of the objects as a 3rd check and if this does not match it returns false. Of course if the object has no Id the hashcode will not match and Equals will return false, but that is not the case here.

Our gethashcode will always derive the hashcode from the primary key Id if it exists, this means that the loaded object and created object will have the same Hashcode (since they have the same Id) and Equals will return true (since they have the same Id).

It seems that NHibernate is picking all this up 100% as it is updating the original record in the Telephone table, which indicates that it figured out that the 2 class instances refer to the same object in the database. But why does it delete the association from the linking table? This is the part which makes no sense to me ...

Ps: For our own use we implemented an EqualsExact method that traverses the object graph and checks that every single property matches, including that of contained objects, but that is not really relevant here.


Top
 Profile  
 
 Post subject: Re: Many-to-Many cascaded updates behaving very strangely
PostPosted: Wed Jul 15, 2009 10:39 am 
Expert
Expert

Joined: Thu Dec 14, 2006 5:57 am
Posts: 1185
Location: Zurich, Switzerland
Which objects are left orphaned ? The modified phone number or the other phone numbers that were previously associated to the person ? If you only add the phone number that has been modified, then all the other phone number will indeed be dettached from person.

_________________
--Wolfgang


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 5 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.