HHH-13129 : Cascaded merge fails for detached bytecode-enhanced entity with uninitialized ToOne
(cherry picked from commit a66ca0463e
)
This commit is contained in:
parent
fb3b710d99
commit
438733d32c
|
@ -12,12 +12,10 @@ import java.util.HashSet;
|
|||
import java.util.Iterator;
|
||||
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.bytecode.enhance.spi.LazyPropertyInitializer;
|
||||
import org.hibernate.bytecode.enhance.spi.interceptor.LazyAttributeLoadingInterceptor;
|
||||
import org.hibernate.collection.spi.PersistentCollection;
|
||||
import org.hibernate.engine.spi.CascadeStyle;
|
||||
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.Status;
|
||||
|
@ -102,25 +100,46 @@ public final class Cascade {
|
|||
final Object child;
|
||||
if ( isUninitializedProperty ) {
|
||||
// parent is a bytecode enhanced entity.
|
||||
// cascading to an uninitialized, lazy value.
|
||||
if ( types[ i ].isCollectionType() ) {
|
||||
// The collection does not need to be loaded from the DB.
|
||||
// CollectionType#resolve will return an uninitialized PersistentCollection.
|
||||
// The action will initialize the collection later, if necessary.
|
||||
child = types[ i ].resolve( LazyPropertyInitializer.UNFETCHED_PROPERTY, eventSource, parent );
|
||||
// TODO: it would be nice to be able to set the attribute in parent using
|
||||
// persister.setPropertyValue( parent, i, child ).
|
||||
// Unfortunately, that would cause the uninitialized collection to be
|
||||
// loaded from the DB.
|
||||
// Cascade to an uninitialized, lazy value only if
|
||||
// parent is managed in the PersistenceContext.
|
||||
// If parent is a detached entity being merged,
|
||||
// then parent will not be in the PersistencContext
|
||||
// (so lazy attributes must not be initialized).
|
||||
if ( eventSource.getPersistenceContext().getEntry( parent ) == null ) {
|
||||
// parent was not in the PersistenceContext
|
||||
continue;
|
||||
}
|
||||
else if ( action.performOnLazyProperty() ) {
|
||||
// The (non-collection) attribute needs to be initialized so that
|
||||
// the action can be performed on the initialized attribute.
|
||||
LazyAttributeLoadingInterceptor interceptor = persister.getInstrumentationMetadata().extractInterceptor( parent );
|
||||
if ( types[ i ].isCollectionType() ) {
|
||||
// CollectionType#getCollection gets the PersistentCollection
|
||||
// that corresponds to the uninitialized collection from the
|
||||
// PersistenceContext. If not present, an uninitialized
|
||||
// PersistentCollection will be added to the PersistenceContext.
|
||||
// The action may initialize it later, if necessary.
|
||||
// This needs to be done even when action.performOnLazyProperty() returns false.
|
||||
final CollectionType collectionType = (CollectionType) types[i];
|
||||
child = collectionType.getCollection(
|
||||
collectionType.getKeyOfOwner( parent, eventSource ),
|
||||
eventSource,
|
||||
parent,
|
||||
null
|
||||
);
|
||||
}
|
||||
else if ( types[ i ].isComponentType() ) {
|
||||
// Hibernate does not support lazy embeddables, so this shouldn't happen.
|
||||
throw new UnsupportedOperationException(
|
||||
"Lazy components are not supported."
|
||||
);
|
||||
}
|
||||
else if ( action.performOnLazyProperty() && types[ i ].isEntityType() ) {
|
||||
// Only need to initialize a lazy entity attribute when action.performOnLazyProperty()
|
||||
// returns true.
|
||||
LazyAttributeLoadingInterceptor interceptor = persister.getInstrumentationMetadata()
|
||||
.extractInterceptor( parent );
|
||||
child = interceptor.fetchAttribute( parent, propertyName );
|
||||
|
||||
}
|
||||
else {
|
||||
// Nothing to do, so just skip cascading to this lazy (non-collection) attribute.
|
||||
// Nothing to do, so just skip cascading to this lazy attribute.
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -131,6 +131,7 @@ public class DefaultDeleteEventListener implements DeleteEventListener, Callback
|
|||
persister,
|
||||
false
|
||||
);
|
||||
persister.afterReassociate( entity, source );
|
||||
}
|
||||
else {
|
||||
LOG.trace( "Deleting a persistent instance" );
|
||||
|
|
Loading…
Reference in New Issue