-->
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.  [ 1 post ] 
Author Message
 Post subject: EntityManager.merge triggers update of unchanged entity
PostPosted: Fri May 23, 2014 5:37 am 
Newbie

Joined: Fri May 23, 2014 5:25 am
Posts: 2
Hi,

I'm experiencing an issue which seems an exact behaviour described in https://hibernate.atlassian.net/browse/HHH-1668. The fix version mentioned in 3.2.0rc5, while I'm running on 3.3.2.GA.

The behaviour is as follows:
* Retrieve entity objects (simpel parent-child OneToMany objects) from the DB
* Map these objects to transfer objects
* Map these objects back to entity objects
* Perform an EntityManager.merge on the parent entity (cascading has been enabled).

This triggers an UPDATE command being sent to the DB (I see the @Version column being incremented), although the data has not changed at all.

Debugging through the Hibernate code reveals the following:
1. The parent object is correctly identified as being unchanged
2. The collection of child objects is identified as begin changed (!! incorrectly).
3. The child objects themselves are also unchanged

The fact that the collection of child objects is dirty lest Hibernate think it needs to update the parent, causing the update command be sent.

I've tried to determine the spot where the PersistentSet is marked as dirty(). This is originates from CollectionType#replaceElements(CollectionType.java:501), where Collection.clear() is called. This marks the collection as dirty. Afterwards, in case both collections are PersistentSet, the original collection is being checked for dirtyness. In case it wasn't dirty, the dirty flag on the target collection is cleared (lines 517-523 of the same class).

However, in the case of an EntityManager.merge, the detached object has it's own collection type, in my case being an ordinary java.util.HashSet. In this case the code of course does nothing and the set is marked as dirty (incorrectly!).

HHH-1668 seems to describe the exact same issue, is marked as fixed in an earlier version than my own version. Am I walking into a regression? Was the issue not fixed at all? For larger sets of object trees, this behaviour is causing massive performance hits.

Update: https://hibernate.atlassian.net/browse/HHH-1401 seems also related to this issue.

Update 2: I've just modified CollectionType.java in the following way:

Code:
        if (original instanceof PersistentCollection) {
            if (result instanceof PersistentCollection) {
                if (!((PersistentCollection) original).isDirty()) {
                    ((PersistentCollection) result).clearDirty();
                }
            }
        }


if replaced with
Code:
final boolean collectionsAreEqual = result.equals(original); // <-- This must be executed before result is modified.

if (original instanceof PersistentCollection) {
            if (result instanceof PersistentCollection) {
                if (!((PersistentCollection) original).isDirty()) {
                    ((PersistentCollection) result).clearDirty();
                }
            }
        } else if (result instanceof PersistentCollection) {
            if (collectionsAreEqual) {
                ((PersistentCollection) result).clearDirty();
            }
        }


(i.e. the second else-if is added).

In this case, the unnecessary updates are not present anymore. However, I'm no expert on Hibernate code and not able to phantom any regressions this may introduce.. Of course, this fix assumes a correct implementation of equals() and hashCode() on the entity objects, however this is a requirement stated in the Hibernate manual, so this shouldn't be an issue. If these methods are not implemented correctly, the same behaviour as the now is executed.

(Of course, this code (if/else-tree) could be reordered to be cleaner code, if this should be the fix, I've omitted this for clarity reasons)

Update: code fix, the equals check has to be performed before modifying "result", otherwise the result of the equals check is always true. The code can probably be optimized for performance reasons, this is currently not done.


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 1 post ] 

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.