HHH-15098 Incorrect behavior when updating managed oneToMany collection on entity with naturalId

This commit is contained in:
Andrea Boriero 2022-03-15 12:13:43 +01:00 committed by Christian Beikov
parent c35f495a7b
commit cb3690466f
1 changed files with 38 additions and 0 deletions

View File

@ -14,10 +14,12 @@ import org.hibernate.ObjectDeletedException;
import org.hibernate.StaleObjectStateException;
import org.hibernate.WrongClassException;
import org.hibernate.bytecode.enhance.spi.interceptor.EnhancementAsProxyLazinessInterceptor;
import org.hibernate.collection.spi.PersistentCollection;
import org.hibernate.engine.internal.Cascade;
import org.hibernate.engine.internal.CascadePoint;
import org.hibernate.engine.spi.CascadingAction;
import org.hibernate.engine.spi.CascadingActions;
import org.hibernate.engine.spi.CollectionEntry;
import org.hibernate.engine.spi.EntityEntry;
import org.hibernate.engine.spi.EntityKey;
import org.hibernate.engine.spi.PersistenceContext;
@ -35,10 +37,13 @@ import org.hibernate.event.spi.MergeEventListener;
import org.hibernate.internal.CoreLogging;
import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.loader.ast.spi.CascadingFetchProfile;
import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.proxy.HibernateProxy;
import org.hibernate.proxy.LazyInitializer;
import org.hibernate.stat.spi.StatisticsImplementor;
import org.hibernate.type.CollectionType;
import org.hibernate.type.EntityType;
import org.hibernate.type.ForeignKeyDirection;
import org.hibernate.type.TypeHelper;
@ -246,6 +251,10 @@ public class DefaultMergeEventListener
super.cascadeAfterSave( session, persister, entity, copyCache );
copyValues( persister, entity, copy, session, copyCache, ForeignKeyDirection.TO_PARENT );
// saveTransientEntity has been called using a copy that contains empty collections (copyValues uses `ForeignKeyDirection.FROM_PARENT`)
// then the PC may contain a wrong collection snapshot, the CollectionVisitor realigns the collection snapshot values with the final copy
new CollectionVisitor( copy, id, session ).processEntityPropertyValues( persister.getPropertyValuesToInsert( copy, getMergeMap( copyCache ), session ), persister.getPropertyTypes() );
event.setResult( copy );
if ( copy instanceof PersistentAttributeInterceptable ) {
@ -257,6 +266,35 @@ public class DefaultMergeEventListener
}
}
private class CollectionVisitor extends WrapVisitor {
CollectionVisitor(Object entity, Object id, EventSource session) {
super( entity, id, session );
}
@Override
Object processCollection(Object collection, CollectionType collectionType) throws HibernateException {
if ( collection instanceof PersistentCollection ) {
final PersistentCollection<?> coll = (PersistentCollection<?>) collection;
final CollectionPersister persister = getSession().getFactory()
.getRuntimeMetamodels()
.getMappingMetamodel()
.getCollectionDescriptor( collectionType.getRole() );
final CollectionEntry collectionEntry = getSession().getPersistenceContextInternal()
.getCollectionEntries()
.get( coll );
if ( !coll.equalsSnapshot( persister ) ) {
collectionEntry.resetStoredSnapshot( coll, coll.getSnapshot( persister ) );
}
}
return null;
}
@Override
Object processEntity(Object value, EntityType entityType) throws HibernateException {
return null;
}
}
private void saveTransientEntity(
Object entity,
String entityName,