-->
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.  [ 6 posts ] 
Author Message
 Post subject: "reassociated object has dirty collection reference&quo
PostPosted: Wed May 03, 2006 10:09 am 
Regular
Regular

Joined: Sun Nov 07, 2004 3:39 pm
Posts: 77
Hibernate 2.1.8, Spring 1.2.6.

In my webapp I have a Parent object which contains a Children collection which I've just switched to 'lazy=true'. I need to store the Parent object in the HTTP session, do something with a Child (in another request) and then retrieve the Parent object from the HTTP session and update the Children collection with the new version of the Child. After switching to 'lazy=true', I was getting LazyInitializationExceptions when trying to use the collection in the Parent reloaded from the HTTP session. I got around this by calling Session.lock() on the Parent object when I retrieved it from the HTTP session, to reassociate it with the Hibernate session. Now, however, when I try to save the Parent record I get the following:

Code:
net.sf.hibernate.HibernateException: reassociated object has dirty collection reference
   at net.sf.hibernate.impl.OnLockVisitor.processCollection(OnLockVisitor.java:53)
   at net.sf.hibernate.impl.AbstractVisitor.processValue(AbstractVisitor.java:69)
   at net.sf.hibernate.impl.AbstractVisitor.processValues(AbstractVisitor.java:36)
   at net.sf.hibernate.impl.AbstractVisitor.process(AbstractVisitor.java:91)
   at net.sf.hibernate.impl.SessionImpl.reassociate(SessionImpl.java:1699)
   at net.sf.hibernate.impl.SessionImpl.lock(SessionImpl.java:1719)


What do I need to do to be able to:

a) In one request, store a parent object with a one-to-many lazy loaded collection in a session.
b) Retrieve this in a second request, update some children.
c) Retrieve the parent object again for further editing in a third request

Alternatively, what am I neglecting to do in the second request which is causing the 'dirty collection reference' problem?


Top
 Profile  
 
 Post subject:
PostPosted: Wed May 03, 2006 9:03 pm 
Expert
Expert

Joined: Thu Dec 23, 2004 9:08 pm
Posts: 2008
Presumably these requests are forwards, rather than separate user-initiated actions? Seeing as objects can't be stored in HTTP sessions, only strings can. If that's the case, just switch to using the open in view pattern, and the problem will automagically disappear.

If these are separate user-initiated actions, then store the ID of the relevant objects in the various sessions, and load them afresh in each action.

_________________
Code tags are your friend. Know them and use them.


Top
 Profile  
 
 Post subject: "reassociated object has dirty collection reference&quo
PostPosted: Thu May 04, 2006 5:32 am 
Regular
Regular

Joined: Sun Nov 07, 2004 3:39 pm
Posts: 77
I don't think I explained myself well. Perhaps a little more detail will help. I have a form where the user can enter details for a Parent record. This form also displays a list of Child records, along with an Add Child button. When the user clicks to Add or Edit a Child, what I need to do is to store the Parent details in the session, then display a Child edit form. The user clicks the save button for the Child record. I now need to retrieve the Parent record from the session and add the Child record to its Children set, and go back to the Parent edit form. A Child record is only ever saved as part of the Parent set (i.e., there's a Children set defined with cascade="all-delete-orphan", and all changes to Child records are persisted via this set).

This all worked fine when the set was defined with 'lazy=false', but it was beginning to get slow. Switching it to 'lazy=true' immediately threw up a LazyInitializationException problem when I retrieved the Parent record from the session and tried to access the children. This is presumably because the Parent record was not actually loaded as part of this Hibernate session, it was from a previous request (I am using an OpenSessionInView filter, incidentally). So what I needed to do was to reattach this Parent to the current Hibernate session. I did this using Session.lock, and all was well and good, the LazyInitializationException went away and the children were loaded. HOWEVER, I found that I then got a "reassociated object has dirty collection reference" exception, if a user did not save the Child record but went back and attempted to save the Parent record. Something is obviously hanging around to cause the dirty collection reference, but what?

The issue with this is that I have to use the session as a temporary holding area for new records, because I can only save the Child records as part of the Parent. When a new Parent record is entered, I need to ensure that any Child records entered are not saved if the Parent record is subsequently cancelled (this would result in 'orphans'), so I can't save the Child records to the database. So I store the Parent record in a session and retrieve it when I need to add the Child records to it. I can then save the whole lot to the database in one go.

So, what I need to be able to do is to store a Parent record in the session in one request and then retrieve it in another request, reattaching it to the new Hibernate session, without subsequently causing the secondary problem of the "reassociated object has dirty collection reference" exception.


Top
 Profile  
 
 Post subject:
PostPosted: Thu May 04, 2006 5:41 pm 
Expert
Expert

Joined: Thu Dec 23, 2004 9:08 pm
Posts: 2008
I'm guessing a little bit here about your exact expected results, but I think what you need to do is inflate and detach the parent object as soon as you've loaded it, at the view/edit parent screen. Use that detached object in the add/edit child screen, then when you get back to the save parent chunk of code, you can either reattach or merge the parent object.

Because you're dealing with a single persistent parent across multiple hibernate sessions, you have to reattach it at each step in order to keep hibernate's session cache happy. However, there's no good reason to use attached objects during the child add/edit step, as you're not interacting with the database. So instead you can completely detach the objects as soon as you've loaded them, and reattach them only when you're doing the save. This has the added bonus of eliminating the risk of an accidental database update, which might happen due to faulty code where you're reattaching objects to the hibernate session.

_________________
Code tags are your friend. Know them and use them.


Top
 Profile  
 
 Post subject:
PostPosted: Fri May 05, 2006 4:19 am 
Regular
Regular

Joined: Sun Nov 07, 2004 3:39 pm
Posts: 77
tenwit wrote:
I'm guessing a little bit here about your exact expected results, but I think what you need to do is inflate and detach the parent object as soon as you've loaded it, at the view/edit parent screen. Use that detached object in the add/edit child screen, then when you get back to the save parent chunk of code, you can either reattach or merge the parent object.


Definitely sounds like you're on the right tracks here. So how do I detach the parent object? I know how to reattach it (with session.lock) but not how to detach it.


Top
 Profile  
 
 Post subject:
PostPosted: Sun May 07, 2006 5:59 pm 
Expert
Expert

Joined: Thu Dec 23, 2004 9:08 pm
Posts: 2008
session.clear() will detach all objects. session.evict() detaches one.

_________________
Code tags are your friend. Know them and use them.


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