-->
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.  [ 8 posts ] 
Author Message
 Post subject: behavior of saveOrUpdate()
PostPosted: Sun Nov 06, 2005 11:51 pm 
Senior
Senior

Joined: Tue Jun 21, 2005 10:18 am
Posts: 135
Location: South Carolina, USA
First of all, yes.. I read the documentation. But I'm confused. So, I'll blow a credit and get you folks to explain it to me :-)

My original understanding:
- Load persistent object in business tier, pass it to UI via RMI
- UI modifies object and passes it back via RMI (EJB call)
- EJB method calls session.saveOrUpdate(detachedObject) and...
- if object's ID matches unsaved-value, it is save()'d, otherwise it is update()'d

What's happening to us:
- Load persistent object in business tier, pass it to UI via RMI
- UI modifies object and passes it back via RMI (EJB call)
- EJB method calls session.saveOrUpdate(detachedObject) and...
- hibernate throws NonUniqueObjectException

Now I'm thinking:
- Load persistent object in business tier, pass it to UI via RMI
- UI modifies object and passes it back via RMI (EJB call)
- EJB method calls session.merge(detachedObject) and...
- I get the behavior I was originally expecting (except that the detached instance is not made a persistent object, which really doesn't matter to me here)

In short, when we want to reattach detached objects in another session, not knowing for sure whether they are new or not (so I want hibernate to decide whether it is a new instance or an existing one), I should be using merge() instead of saveOrUpdate().

Am I on the right track here, or am I barking up the wrong tree?


Top
 Profile  
 
 Post subject:
PostPosted: Mon Nov 07, 2005 12:24 am 
Hibernate Team
Hibernate Team

Joined: Mon Aug 25, 2003 9:11 pm
Posts: 4592
Location: Switzerland
Quote:
In short, when we want to reattach detached objects in another session, not knowing for sure whether they are new or not (so I want hibernate to decide whether it is a new instance or an existing one), I should be using merge() instead of saveOrUpdate().


No, both are transparent wether the object (graph) you are passing in is transient or detached. The guaranteed state of your data is to be persistent afterwards.

saveOrUpdate() simply reattaches the detached instance - it is considered persistent again. (Or it tries to make transient stuff persistent, but that's not the issue.)

Reattachment might clash with an identical persistent instance (database identity) that is already in the Session, for whatever reason (already loaded, for example). This is why you need the merge() model, if you can't guarantee that the Session does not contain an identical instance when you saveOrUpdate().

merge() merges data and returns a persistent instance, depending on a set of rules as outlined in the docs.

Both allow different programming models and are used separate or together. The old method name for merge() was saveOrUpdateCopy() in native Hibernate. EJB 3.0 persistence only supports the merge() model.


Top
 Profile  
 
 Post subject:
PostPosted: Mon Nov 07, 2005 9:21 am 
Senior
Senior

Joined: Tue Jun 21, 2005 10:18 am
Posts: 135
Location: South Carolina, USA
christian wrote:
Reattachment might clash with an identical persistent instance (database identity) that is already in the Session, for whatever reason (already loaded, for example). This is why you need the merge() model, if you can't guarantee that the Session does not contain an identical instance when you saveOrUpdate().


This seems to be what we're seeing. We're not sure how the clashing object is getting loaded in the second session, but that's another issue entirely (probably an eager fetch that we haven't located yet). Given this, though, I'm confused as to why one would really want to saveOrUpdate(). After all, if merge() is going to avoid the NonUniqueObjectException (and achieve nearly the same effect), why not prefer it to saveOrUpdate()? The only immediate downside that I see is that the original instance is not itself reattached, something that's easily dealt with by reassigning a pointer:

Code:
myObject = (MyObjectType)session.merge(myObject);


Top
 Profile  
 
 Post subject:
PostPosted: Mon Nov 07, 2005 9:35 am 
Hibernate Team
Hibernate Team

Joined: Mon Aug 25, 2003 9:11 pm
Posts: 4592
Location: Switzerland
You might have other parts of the graph that are still detached, and are not reattached (because cascading to this part is not enabled, probably).

If you merge and get a new instance, all the "older" detached instances will point to something that is obsolete. Of course you could just ignore that new instance and continue using the old graph and merge whenever you need.

It's really your choice. You could say that saveOrUpdate() was the original strategy. Then saveOrUpdateCopy() was needed to deal with the "object is already persistent" problem. Now we have merge() that can, likely, replace both.


Top
 Profile  
 
 Post subject:
PostPosted: Mon Nov 07, 2005 10:55 am 
Senior
Senior

Joined: Tue Jun 21, 2005 10:18 am
Posts: 135
Location: South Carolina, USA
christian wrote:
You might have other parts of the graph that are still detached, and are not reattached (because cascading to this part is not enabled, probably).

Is this different than saveOrUpdate()? If I have a graph of two objects (Parent and Child) with a one-to-one association, I would think that if the cascade from Parent to Child is not cascade="save-update", then I saveOrUpdate(parent), I would expect that parent would be reattached, but the child would not. Likewise with merge (except now the correct setting is cascade="merge"), I would expect parent = session.merge(parent) to result in the parent being attached with its child still detached.

If the casecades are set up, I would expect that Parent and Child would both end up reattached, except of course, that in merge, the persistent instance is returned, rather than the passed-in object itself, and the detached instance still exists.

Is there a difference in behavior here? (Assume for the moment that neither parent nor child is loaded in the second session)


Top
 Profile  
 
 Post subject:
PostPosted: Mon Nov 07, 2005 11:11 am 
Hibernate Team
Hibernate Team

Joined: Mon Aug 25, 2003 9:11 pm
Posts: 4592
Location: Switzerland
Correct. The problem is that while you reattach the parent, the child might be "somewhere else". This doesn't work well with merge(), you get a new parent and your old parent _and_ child are obsolete now.


Top
 Profile  
 
 Post subject:
PostPosted: Mon Nov 07, 2005 11:13 am 
Hibernate Team
Hibernate Team

Joined: Mon Aug 25, 2003 9:11 pm
Posts: 4592
Location: Switzerland
By the way, start thinking about unidirectional pointers. Parent/child is a bad example. You simply have to two instances, A and B. Instance A has a pointer to instance B. If you merge(B), then instance A does not get a pointer to the new B returned by the merge.


Top
 Profile  
 
 Post subject:
PostPosted: Mon Nov 07, 2005 2:10 pm 
Senior
Senior

Joined: Tue Jun 21, 2005 10:18 am
Posts: 135
Location: South Carolina, USA
Thanks for all your help, Christian.


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