-->
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: NonUniqueObjectException and session-per-request-with-detach
PostPosted: Sat Mar 20, 2004 2:07 pm 
Beginner
Beginner

Joined: Fri Oct 10, 2003 10:12 am
Posts: 39
hello,

could someone explain how you are supposed to use the session-per-request-with-detached-objects pattern described in the wiki? the only way it would seem to work is if there are no duplicate objects passed into the final update session, otherwise a NonUniqueObjectException is thrown. this makes it pretty useless unless you're using a simple object graph.

take for example the problem i am working on - i have an order which has multiple products that have associations to companies . if i try to add two products that have the same company, the session will complain that the companies being associated with it were loaded in differnent sessions.

is there a way around this problem, or should i migrate to the session-per-application-transaction pattern?

thanks,
cam


Top
 Profile  
 
 Post subject:
PostPosted: Sat Mar 20, 2004 2:26 pm 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 12:50 pm
Posts: 5130
Location: Melbourne, Australia
It is usually pretty easy to ensure uniqueness, by lock()ing previously retrieved instances in each new session.


Top
 Profile  
 
 Post subject:
PostPosted: Sat Mar 20, 2004 2:47 pm 
Beginner
Beginner

Joined: Fri Oct 10, 2003 10:12 am
Posts: 39
so it's time for some manual coding? damn - it'd being trying to avoid that. do locks get cascaded in any way?

thanks,
cam


Top
 Profile  
 
 Post subject:
PostPosted: Tue Jun 22, 2004 1:19 pm 
Beginner
Beginner

Joined: Tue Oct 28, 2003 12:09 pm
Posts: 46
Pushing this thread back up...I've taken a look at the idea of manually locking objects and it becomes almost impossible when you combine the idea of cascading in with the locking.

It's my understanding (from reading and a simple test or two) that hibernate.lock(object, LockMode.NONE) doesn't cascade lock all objects into the session. If that's incorrect, please ignore the rest of my post and tell me so.

My troubles come from putting hibernate objects into a session-persisted Struts Form object.

So, my example:

Code:
A a = new A();
B b = hibernate.load(b);
a.setB(b);
dynaForm.set("A", a);


and in the next http request after my session has been closed in the session per request/detached object pattern:

Code:
A a = (A) dynaForm.get("A");
hibernate.saveOrUpdate(a);


This causes a NonUniqueObjectException because of cascades to other properties cause a copy of my "b" object to be loaded several cascade levels deep before the save gets to my "b" property which I loaded in the previous session. ie: it cascades a->c->d->b and that last "b" is the same object (same id) as the "b" loaded in the previous code.

I tried to do both saveOrUpdateCopy and dynamic-insert/dynamic-update=true and several mixtures of the two, but that either didn't work or caused a LazyInitalizationException because "a"'s collections are loaded to check to see if they have changed. As a side note, it seems odd that it would try to load those collections since I've asked it only to generate an update for things that have changed. If they haven't been loaded, they haven't been changed...no?

Looking into Spring, the best case solution seems to be to decouple the form/hibernate objects so we don't run into this problem but it seems like hibernate handles all other edge cases I've run into like this gracefully, so it would be nice if it would do so in this case too. The mantra up to this point has been, just-do-it-with-hibernate-and-let-it-solve-your-problems and now that I've gotten used to it...I want it to solve this problem for me too. :)

Thoughts?
Is anyone else out there doing session persisted struts forms with hibernate objects in them and running into problems like this?
If so, how did you solve the problems?

-mp


Top
 Profile  
 
 Post subject:
PostPosted: Tue Jun 22, 2004 1:24 pm 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 12:50 pm
Posts: 5130
Location: Melbourne, Australia
lock() cascades when cascade="save-update" or above.


Top
 Profile  
 
 Post subject:
PostPosted: Wed Jun 23, 2004 12:21 pm 
Beginner
Beginner

Joined: Tue Oct 28, 2003 12:09 pm
Posts: 46
Ahhh...I didn't realize that locking listened to those flags as well. That helps. I must have my cascades set up slightly incorrectly then...I'll go check.

One thought/request:

Right now if you call .lock on a transient instance, an exception is thrown. I'd be happy if it wouldn't throw the exception and walk the cascades locking all objects into this session.

Reason:
I often create a new object with many properties that are existing objects that need to be locked.

As it is now, I have to walk all those properties, locking each one into the new session.

If it would work on a transient instance, I could just lock the object and it would walk the cascades and lock things for me. Seems that the actual .lock on the transient instance (disregarding cascades) could be a NOOP without hurting anyone's feelings?

Don't know if this conflicts with other uses of the .lock function...but if it doesn't it would be a nice-to-have.

-mp


Top
 Profile  
 
 Post subject:
PostPosted: Fri Jun 25, 2004 11:37 am 
Beginner
Beginner

Joined: Tue Oct 28, 2003 12:09 pm
Posts: 46
Just in case anyone is reading this to address their own problems, here is the pattern we went with...

Each of my actions calls super.execute before doing anything else. That calls my own lockObjects method which walks the DynaActionForm, locking all hibernate objects (and if they're transient, it uses the meta data to cascade the lock to all entity/collections as well).

That way I don't have to worry myself thinking about which session an object was loaded in.

One warning, be careful because the locked objects will be stale WRT the database state...when you lock them into the form they will be inserted into the session cache and any edits done by other pages won't appear until the form is discarded.

-mp


Top
 Profile  
 
 Post subject:
PostPosted: Tue Jun 29, 2004 2:37 pm 
Beginner
Beginner

Joined: Tue Oct 28, 2003 12:09 pm
Posts: 46
From the hibernate documentation:

"The lock() method allows the application to reassociate an unmodified
object with a new session."

Note the "unmodified."

So, this leaves us in a state where we have loaded an object into a struts form (session persisted) and locked the objects upon submit so we can commit these previously loaded objects (+ changes) to the db.

But, since the objects have been locked, hibernate thinks they haven't changed so won't write the changes to the database upon a saveOrUpdate() call.

Has anyone worked around this problem?

-mp


Top
 Profile  
 
 Post subject:
PostPosted: Tue Jun 29, 2004 4:19 pm 
Beginner
Beginner

Joined: Tue Oct 28, 2003 12:09 pm
Posts: 46
http://hibernate.org/168.html

Is extremely nice and something I wish I had found earlier. But, hey, I suck at finding things on the web. (I ended up finding a blog by gavin that addressed this and then came back to the wikki using his words to search. :P )

I also just bought the book so am going to bury my head for a few hours.

I'll let you know if I need my questions answered further...so don't waste time with them right now.

Thanks!
-mp


Top
 Profile  
 
 Post subject:
PostPosted: Tue Jun 29, 2004 6:10 pm 
Beginner
Beginner

Joined: Tue Oct 28, 2003 12:09 pm
Posts: 46
ok, that clarified things a bit. Now a hopefully more clear question.

Is there anyway to deal with modified dettached objects in the following scenario?

Code:

-Load object A in Session 1 (which causes child object B to be loaded)

-close Session 1

-Modify object A

-open Session 2

-base on the modified state of A, load object C be set as a child entity of A (which causes object B to be loaded as a child entity of C)

-saveOrUpdate object A (which cascades save-update to B).

-an exception is thrown because B was already loaded in this session.




The docs say that you have to do an update to attach a modified-dettached object but I can't do the update before object B is loaded again because certain constraints won't be satisfied.

A similar chicken/egg problem exists when messing with transient objects that have non-transient children loaded in session1 to be presented to the user and then more non-transient children loaded in session2 before the save happens.

glurf?
-mp

ps. Chapter 5 is well written, any timeline for Chapter 8 of the book? :)


Top
 Profile  
 
 Post subject:
PostPosted: Thu Aug 19, 2004 3:53 pm 
Newbie

Joined: Thu Aug 19, 2004 7:57 am
Posts: 14
gavin wrote:
It is usually pretty easy to ensure uniqueness, by lock()ing previously retrieved instances in each new session.


What do you mean? How would I do that?

Code:
Object o = "retrive an object from the database using hibernate query"
currentSeesion.lock(o)... or something like that??

What does that do? Won't hibernate pick up an object from the cache if I query again?

Code:
Object o1 = "retrive an object from the database using hibernate query"
Object o2 = "retrive anpther object from the database using same exact query"


Shouldn't o1 == o2? Even from an identity perspective, I'd think so. Ah, may I need to implement hashCode and equals to make this work??

My original post is here...

http://forum.hibernate.org/viewtopic.php?t=933689

_________________
Andy Czerwonka


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.