-->
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.  [ 2 posts ] 
Author Message
 Post subject: Why can't I lock/reattach an entity with a dirty collection?
PostPosted: Mon Aug 02, 2010 5:11 pm 
Newbie

Joined: Fri Oct 06, 2006 8:09 pm
Posts: 5
Location: Costa Mesa, CA
We are using Hibernate 3.3.2.GA, with optimistic locking via @Version and the session per request pattern (and thus detached entity object graphs).

We have a very complex object graph consisting of carts, orders, line items, sub line items, payments, delivery, sub line item deliveries, etc. In most situations, our cart executes against a single order. However, there are cases where multiple orders can be involved. Our orders can be fairly large in terms of the number of line items, sub items, etc. As a result, as users navigate the application we only load the orders they request.

The issue gets more complex if two orders (e.g. order #1 and #2) are involved in multiple carts. Why? Some entities in the object graph (e.g. carts, payments, deliveries, etc) can span orders and transactions. Consider a multiple-step/session cart where we load order #1, associate it with a new cart and detach the object graph. The user subsequently requests elements from order #2 be loaded into the new cart. So, we load order #2, associate it with the same/new cart and detach the object graph.

Now, if in a previous cart/transaction, orders #1 and #2 shared a (eg) delivery, when we load #2 and its associated delivery, in order to avoid two instances of this same delivery in our detached object graph, we need to re-attach the previously loaded delivery to the new session, prior to loading order #2.

Since we are not ready to persist changes to the database yet, and because this delivery may be dirty, we choose to use Hibernate’s “lock” API (as opposed to refresh, load, merge, update, etc) to re-attach the delivery in our graph to the current session.

All this works great except that if our delivery entity has a pesisted collection that has been modified, a “reassociated object has dirty collection” Hibernate exception is thrown.

We could work around this situation by adding a new collection to our delivery entity that maintained changes to the pesisted collection, then just prior to calling “merge” we could move the changes to the persistence collection. However, as I mentioned we have a complex object graph... that involves 10 entities with a total of 23 persisted collections we’d have to manage this way for this one aspect of our system.

As an experiment, I commented out one line in the org.hibernate.event.def.OnLockVisitor class, processCollection method (below) to no longer throw the exception.

Code:
                    if ( persistentCollection.isDirty() ) {
                        // Don't throw exception hack
                        // throw new HibernateException( "reassociated object has dirty collection" );
                    }
                    reattachCollection( persistentCollection, type );

and returned early from org.hibernate.event.def.DefaultLockEventListener class, onLock method (below)
Code:
            if ( !ForeignKeys.isNotTransient( event.getEntityName(), entity, Boolean.FALSE, source ) ) {
                return; // Return early hack
//                throw new TransientObjectException(
//                        "cannot lock an unsaved transient instance: " +
//                        persister.getEntityName()
//                );
            }

With these two changes, I was able to lock / re-attach all the necessary entities in our detached object graph, and subsequently was able to merge the entire graph successfully.

My questions to the Hibernate team are:

1) Is there already existing functionality that could achieve the same results (e.g. re-attach detached entities that contain dirty persistence collections to a new session )?

2) Would they consider adding another org.hibernate.LockMode type (e.g. DIRTY) that would support the behavior I’ve described above?


Top
 Profile  
 
 Post subject: Re: Why can't I lock/reattach an entity with a dirty collection?
PostPosted: Thu Aug 12, 2010 6:41 am 
Newbie

Joined: Tue May 26, 2009 6:01 am
Posts: 3
Location: Hannover, Germany
At our company we are facing a very similar problem. We are using Hibernate 3.4.0.GA and don't want to load the entire object graph with one entire JPQL that includes many join fetches. For performance reasons (to reduce the size of the resultset Hibernates will receive by the created SQL-statement) we first select only one part of the graph with one JPQL and right after this we execute a second one for the rest of the graph.

Now, before we call session.clear() to detach the entire graph we have to make sure that both selected parts get to know each other by initializing the assoziations that exist between these parts. To achieve this it might be possible to simply call Hibernate.initialize(thePersistentCollection) to initialize these assoziations. But with a one-to-many-assozaition this call produces another SQL-SELECT instead of picking up the allready selected entities from the persistence context. Generally this behaviour is allright, because Hibernate has no chance of knowing weather all assoziated entities have allready been selected, because the foreigen-key for the one-to-many-assoziation gets stored at the to-many-side.

The major point in this case is that I know that all entities have allready been selected that belong to this assoziation and that I want to avoid this additional and useless SQL-SELECT. I tryed to avoid this by simply doing the following:

Code:
...
firstPartOfTheGraph.setAssoziationToSecondPartOfTheGraph(secondPartOfTheGraph);
session.clear();
...


So I manually initialize the assoziation and then detach the graph right afterwards. So Hibernate doesn't get a chance to execute the SQL-SELECT befor I detach.

The problem now pops up when I try to reatach the object-garph later. Because Hibernate seems to detect the manually initialized assoziation as dirty it fails with the HibernateException: "reassociated object has dirty collection". So I don't get the chance to manually instanciate an assoziation without either producing an additional and unnecessary SQL-SELECT or getting this HibernateException. I think for performance reasons it is very useful to manually instanciate assoziations and from this point of view there really seems to be a need for a LockMode.DIRTY as described above or something similar.

Best regards
Maximilian


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