HHH-6361: Patch ensuring that collection events have the correct stored

snapshot after merging a detached entity into the persistencecontext
This commit is contained in:
Erik-Berndt Scheper 2012-10-29 17:46:00 -04:00 committed by brmeyer
parent 5c562411e6
commit 7bb43baf0b
2 changed files with 81 additions and 1 deletions

View File

@ -264,6 +264,20 @@ public final class CollectionEntry implements Serializable {
return snapshot;
}
/**
* Reset the stored snapshot for both the persistent collection and this collection entry.
* Used during the merge of detached collections.
*
* @param collection the persistentcollection to be updated
* @param storedSnapshot the new stored snapshot
*/
public void resetStoredSnapshot(PersistentCollection collection, Serializable storedSnapshot) {
LOG.debugf("Reset storedSnapshot to %s for %s", storedSnapshot, this);
snapshot = storedSnapshot;
collection.setSnapshot(loadedKey, role, snapshot);
}
private void setLoadedPersister(CollectionPersister persister) {
loadedPersister = persister;
setRole( persister == null ? null : persister.getRole() );

View File

@ -29,9 +29,12 @@ import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;
import org.dom4j.Element;
import org.dom4j.Node;
@ -40,6 +43,7 @@ import org.hibernate.Hibernate;
import org.hibernate.HibernateException;
import org.hibernate.MappingException;
import org.hibernate.collection.spi.PersistentCollection;
import org.hibernate.engine.spi.CollectionEntry;
import org.hibernate.engine.spi.CollectionKey;
import org.hibernate.engine.spi.EntityEntry;
import org.hibernate.engine.spi.Mapping;
@ -49,6 +53,7 @@ import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.internal.util.MarkerObject;
import org.hibernate.internal.util.collections.ArrayHelper;
import org.hibernate.internal.util.collections.CollectionHelper;
import org.hibernate.metamodel.relational.Size;
import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.persister.collection.QueryableCollection;
@ -512,12 +517,73 @@ public abstract class CollectionType extends AbstractType implements Association
if ( ! ( ( PersistentCollection ) original ).isDirty() ) {
( ( PersistentCollection ) result ).clearDirty();
}
if (elemType instanceof AssociationType) {
preserveSnapshot(( PersistentCollection )original, ( PersistentCollection ) result, (AssociationType) elemType, owner, copyCache, session);
}
}
}
return result;
}
private void preserveSnapshot(PersistentCollection original ,PersistentCollection result, AssociationType elemType, Object owner,
Map copyCache, SessionImplementor session) {
Serializable originalSnapshot = original.getStoredSnapshot();
Serializable resultSnapshot = result.getStoredSnapshot();
Serializable targetSnapshot;
if (originalSnapshot instanceof List) {
targetSnapshot = new ArrayList(((List) originalSnapshot).size());
for (Object obj : (List) originalSnapshot) {
((List) targetSnapshot).add(elemType.replace(obj, null, session, owner, copyCache));
}
} else if (originalSnapshot instanceof Map) {
if (originalSnapshot instanceof SortedMap) {
targetSnapshot = new TreeMap(((SortedMap) originalSnapshot).comparator());
} else {
targetSnapshot = new HashMap(
CollectionHelper.determineProperSizing( ((Map) originalSnapshot).size()),
CollectionHelper.LOAD_FACTOR);
}
for (Map.Entry<Object, Object> entry : ((Map<Object,Object>) originalSnapshot).entrySet()) {
Object key = entry.getKey();
Object value = entry.getValue();
Object resultSnapshotValue = (resultSnapshot == null) ? null : ((Map<Object,Object>) resultSnapshot).get(key);
if (key == value) {
Object newValue = elemType.replace(value, resultSnapshotValue, session, owner, copyCache );
((Map) targetSnapshot).put(newValue, newValue);
} else {
Object newValue = elemType.replace(value, resultSnapshotValue, session, owner, copyCache );
((Map) targetSnapshot).put(key, newValue);
}
}
} else if (originalSnapshot instanceof Object []) {
Object [] arr = ( Object []) originalSnapshot;
for (int i=0; i< arr.length; i++) {
arr[i] = elemType.replace(arr[i], null, session, owner, copyCache );
}
targetSnapshot = originalSnapshot;
} else {
// retain the same snapshot
targetSnapshot = resultSnapshot;
}
CollectionEntry ce = session.getPersistenceContext().getCollectionEntry(result);
if (ce != null) {
ce.resetStoredSnapshot(result, targetSnapshot);
}
}
/**
* Instantiate a new "underlying" collection exhibiting the same capacity
* charactersitcs and the passed "original".