-->
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.  [ 11 posts ] 
Author Message
 Post subject: many-to-many: undesired deletes
PostPosted: Wed Mar 31, 2004 5:11 am 
Newbie

Joined: Fri Feb 20, 2004 7:37 am
Posts: 12
Sorry if this is a stupid question - I can't find the node in my head.

I have a many-to-many association between two classes A and B.
A sets inverse="false", B has inverse="true" and both have cascade="none".
I have the methods A.getBs() and B.getAs() to get the associated collections from both sides.

Now I'm working with an object A in different sessions. It's loaded in an EJB and transfered to client. I do not initialize the collection of Bs before transfering it. On the client A is changed, transfered back to the EJB and updated to the database with a simple session.update(A) using a different Hibernate session.
Now Hibernate deletes all my associations to the Bs (it does a "delete from <collection_table> where a_id=?").

I assume that Hibernate does the right thing - the collection of Bs in A isn't initialized.
But how can I update A and leave the associations untouched? I don't want to transfer the Bs down to the client and back (performance, network traffic, ...).

Many thanks for any help.


Top
 Profile  
 
 Post subject:
PostPosted: Wed Mar 31, 2004 10:14 am 
Hibernate Team
Hibernate Team

Joined: Sun Sep 14, 2003 3:54 am
Posts: 7256
Location: Paris, France
do a specific addBsToA() and do the job in your server layer

_________________
Emmanuel


Top
 Profile  
 
 Post subject:
PostPosted: Wed Mar 31, 2004 4:39 pm 
Newbie

Joined: Fri Feb 20, 2004 7:37 am
Posts: 12
Hmm, I don't understand your point.
Adding B's to A works fine. I have such a function in my server layer where I do all the operations in one session (loading A, A.getBs().add(newB), ...).

My problem is when I just update A all existing associations to the B's are deleted.

I've tried to set both sides to inverse="true". Then the B's are not deleted.

But now I can't add or remove any associations. I've tried
A.getBs().add(newB)
newB.getAs().add(A)
session.flush()
=> no insert in the collection table.


Top
 Profile  
 
 Post subject:
PostPosted: Thu Apr 01, 2004 4:00 am 
Hibernate Team
Hibernate Team

Joined: Sun Sep 14, 2003 3:54 am
Posts: 7256
Location: Paris, France
Do what I told you and in the server side
load A with it's Bs collection before adding new B, then Hibernate won't delete previous links

_________________
Emmanuel


Top
 Profile  
 
 Post subject:
PostPosted: Thu Apr 01, 2004 5:52 am 
Newbie

Joined: Fri Feb 20, 2004 7:37 am
Posts: 12
Emmanual,
I thank you for your help and patience but we are not talking about the same thing.
I'll describe my problem again and in more detail:

On the server I load A:
Code:
A a = new A();
session.load(a, new Integer(<id>));


I don not load the B's here. No
Code:
// a.getBs();
// hibernate.initialize();


The A is transfered to the client. On the client I change a field - say:
Code:
a.setName("something");


The object is given back to the server for updating the changes:
Code:
session.saveOrUpdate(a);
session.flush();


Now two SQL-statements are executed:
Code:
update a set name=... where id=...
delete from <collection_table> where a_id=...


The second statement is my problem - it wipes all associations to Bs.
I think the reason is that the A is loaded in one session and updated in a different session.
At the moment I have the following solution - when updating the A:
Code:
A a2 = new A();
session.load(a2, a.getId());  //load the same A again in this session
a2.setData(a);   //copies all fields from a to a2
a2.update();
session.flush();


Now the delete-statement is not executed! It works but is this the only way to do it?

Thanks.


Top
 Profile  
 
 Post subject:
PostPosted: Thu Apr 01, 2004 12:31 pm 
Hibernate Team
Hibernate Team

Joined: Sun Sep 14, 2003 3:54 am
Posts: 7256
Location: Paris, France
Are you doing something weird with Bs collection while detached ?
Is your getter/setter safe (no null set instead of the colelction set by hibernate...)

_________________
Emmanuel


Top
 Profile  
 
 Post subject:
PostPosted: Fri Apr 02, 2004 7:01 am 
Newbie

Joined: Fri Feb 20, 2004 7:37 am
Posts: 12
Ok, I've left out one detail in my description above:
On the client side I have a higher-level business object where I copy the contents of A.
When updating the business object I create a new A object which is then transferred to the server. So the A loaded is different from the A updated and the collection of Bs is definitely null.

Hmm, are you sure that it would work when I would always use the same A? Even if it is transfered and marshalled through/over several proxies and stubs.


Top
 Profile  
 
 Post subject:
PostPosted: Fri Apr 02, 2004 1:45 pm 
Hibernate Team
Hibernate Team

Joined: Sun Sep 14, 2003 3:54 am
Posts: 7256
Location: Paris, France
If you reassociate the objet graph to a new session, yes.

_________________
Emmanuel


Top
 Profile  
 
 Post subject: Is the Answer then that you must update?
PostPosted: Tue Apr 06, 2004 4:50 pm 
Newbie

Joined: Wed Mar 24, 2004 7:40 pm
Posts: 18
I have an identical situation and identical problem, so the answer to this question would answer my question as well. I think the question was answered, but I just want to make sure:

Quote:
alpha137:Hmm, are you sure that it would work when I would always use the same A? Even if it is transfered and marshalled through/over several proxies and stubs.


Quote:
emmanuel: If you reassociate the objet graph to a new session, yes.


The way I understand this, this means that if I use a different INSTANCE of class A to update the record corresponding to a1, the null collection of Bs will always delete all the A-to-B associations in the collection table.

By implication, this means that if I do this:

Code:
//session 1
A a1 = new A();
session1.load(a1, new Integer(<id>));


Code:
//go to client (web) tier where fields from a1 are dehydrated and cached


Code:
// session 2
A a2 = <rehydrate an A from cached fields>
session.saveOrUpdate(a2);
session.flush();


I will always do this:
Code:
update a set name=... where id=...
delete from <collection_table> where a_id=...


So the best practical solution to this problem, which will keep my B collection intact is this:

Code:
A a2 = new A();
session.load(a2, a.getId());  //load the same A again in this session
a2.setData(a);   //copies all fields from a to a2
a2.update();
session.flush();


All this makes sense, but I guess what I am looking for is some kind of "please don't update this" placeholder to put in the collection of Bs. It seems like when I do a lazy, uninitialized load on the collection of Bs in a1, it must contain a Hibernate-specific implementation if an uninitialized collection that serves as this "please don't update this" placeholder.

Thus, it would be nice if we could get ahold of one of those to do something like this in session2:

Code:
// session 2
A a2 = <rehydrate an A from cached fields>
a2.setBs(<please don't update this placeholder>);//uninit'd collection?
session.saveOrUpdate(a);
session.flush();


Which would keep hibernate from deleting our B associations.

Is there anything like this possible?


Top
 Profile  
 
 Post subject:
PostPosted: Tue Apr 06, 2004 5:04 pm 
Newbie

Joined: Wed Mar 24, 2004 7:40 pm
Posts: 18
Additionally, lets say A has an additional association to a group of Cs, this time one-to-many (instead of many-to-many). How come when I do a essentially this same pattern, my Cs do not get erased.

That is, when I have this:
Code:
<class name="A" >
        <id>...</id>
        <set name="Bs"
            lazy="true"
            table="collection_table"
            cascade="delete">
            <key column="A_ID"/>
            <many-to-many class="B" column="B_ID"/>
        </set>
       <set name="Cs"
            lazy="true"
            inverse="true"
            cascade="delete">
            <key column="A_ID"/>
            <one-to-many class="C"/>
        </set>
</class>


...and I do this:
Code:
//session 1
A a1 = new A();
session1.load(a1, new Integer(<id>));


Code:
//go to client (web) tier where fields from a1 are dehydrated and cached


Code:
// session 2
A a2 = <rehydrate an A from cached fields>
session.saveOrUpdate(a2);
session.flush();


...Hibernate does this:
Code:
update a set name=... where id=...
delete from <collection_table> where a_id=...


...but does not do this:
Code:
delete from <Cs table> where a_id =...


Top
 Profile  
 
 Post subject: Additional Information?
PostPosted: Tue Apr 13, 2004 4:27 pm 
Newbie

Joined: Wed Mar 24, 2004 7:40 pm
Posts: 18
Is there additional information I can add to the above 2 questions to help anyone answer them? The two questions:

1) Is there a way to turn off the deletes for my Bs when updating A?
2) When I update my As, my Bs get deleted and not my Cs; why?

Thanks again.


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