-->
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: Cascading detective story
PostPosted: Thu Dec 08, 2005 12:35 pm 
Regular
Regular

Joined: Thu Oct 27, 2005 8:06 am
Posts: 55
Location: München, Germany
Recently, I had a problem with a plain vanilla cascading update for which I haven't found an explanation. I found a way around it, so I'm not asking for debugging help, but for deeper insight and wild ideas.

The following classes and relationships are involved:

P has one-to-many to RP, mapped as cascade="all"
RP has many-to-one to R
R has one-to-many to A

My question is:

In which cases can a saveOrUpdate on P with cascade="all" to RP have different semantics from saveOrUpdate on P without a cascade, followed by a hand-coded iteration of saveOrUpdate on the RP's contained in P?

For the curious, the detective story follows.

The transaction I'm talking about creates a few RP's, links them to an existing P, and connects them to the R's. R's and A's are already on the database and are not modified.

After building up the object graph, I issued saveOrUpdate to P, and got an InvalidArgumentException on the getter method of the Set in R containing the A's. I was a little bit puzzled, as the R's together with their A's had been entered with the help of Hibernate hours before, so if there was anything wrong with the getter, why hadn't it complained?

To find the object that was at fault in my graph, I inserted a few LoC immediately before my saveOrUpdate, traversing the P - RP - R - A graph and writing a nice line into the log for each object found. If anything was wrong with the data structure, I hoped this log would be written up to the corrupted object, and I would know where to look for my bug. Nothing like that happened. The entire object graph was lazily loaded without complaint. After that, the saveOrUpdate on the same graph bombed.

I put logging to debug mode and looked what Hibernate was doing. Immediately after receiving the saveOrUpdate to P, it cascaded to RP. Fine. Immediately after that, it cascaded to saveOrUpdate for an R, which was less fine. I was even less pleased to find that the R it tried to save was a transient instance containing a null id, so I concluded that somewhere my software had constructed a new R, without properly initializing it. This would lead to a non-initialized collection of A's, and explain the error.

I couldn't explain where this empty R came from. So I inserted a log into the constructor for R, which only gave me the R records I had expected, all containing nice id's. To find out where that mysterious empty R came from, I mentally prepared for a long debugging night.

I took one final chance. I removed cascade="all" from the R - RP relationship and coded the cascade myself. After calling saveOrUpdate for R, I iterated on the RP's in R, calling saveOrUpdate for each of them. And lo and behold, this worked, and my objects got stored smoothly.

So I somehow solved the problem, but I'm only partly happy. The code works, but I don't really know why. I feel like at the end of silence of the lambs, where the victim has been saved, but the murderer is still hiding somewhere. I had always considered a cascade on a collection to be semantically equivalent to a hand-coded iteration over the collection.

Please note that I don't suggest Hibernate is at fault. I assume the problem is in my code, and am just wondering why Hibernate complains in one case, and doesn't in another.


Top
 Profile  
 
 Post subject:
PostPosted: Thu Dec 08, 2005 12:44 pm 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 12:50 pm
Posts: 5130
Location: Melbourne, Australia
Quote:
In which cases can a saveOrUpdate on P with cascade="all" to RP have different semantics from saveOrUpdate on P without a cascade, followed by a hand-coded iteration of saveOrUpdate on the RP's contained in P?



Well, always, since the operation gets applied to children first when cascading.


Top
 Profile  
 
 Post subject:
PostPosted: Thu Dec 08, 2005 1:52 pm 
Regular
Regular

Joined: Thu Oct 27, 2005 8:06 am
Posts: 55
Location: München, Germany
Thanks, Gavin, good to know.

So I tried to mimick Hibernate's cascading logic, putting my hand-coded saveOrUpdate of the RP's in front of that of the P. But Hibernate complained, when storing the first RP, that the P it refers to is still transient. As the only way of getting P non-transient is by saving it, it looks to me that there is no way to achieve the exact semantics of a cascade by hand-coding.


Top
 Profile  
 
 Post subject:
PostPosted: Thu Dec 08, 2005 1:59 pm 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 12:50 pm
Posts: 5130
Location: Melbourne, Australia
Excuse me, I lie. Children get saved last. Duh.


Top
 Profile  
 
 Post subject: Putting on sackcloth and ashes
PostPosted: Thu Dec 08, 2005 3:42 pm 
Regular
Regular

Joined: Thu Oct 27, 2005 8:06 am
Posts: 55
Location: München, Germany
Sorry to bother you, I made a stupid beginner's mistake.

In my mapping file, I had erroneously mapped P to R, instead of RP. My Java classes were coded the right way, so the actual links were to RP. Therefore, when following the links by Java code, the RP objects were found and stored. When Hibernate followed the links, it got confused and obviously treated the RP's as if they were R's. Of course the getters for R's attributes were missing.

The only tiny argument in my favor is that I would have expected Hibernate to start complaining when it realized that the one-to-many class I had declared didn't match the type of the Java Set. Therefore I didn't even bother to check my P mapping file.


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.