HHH-14387 Alternative fix for deletion of bytecode lazy collections, by creating PersistentCollection for deletedState
This commit is contained in:
parent
41ac1f8e88
commit
a83ff54671
|
@ -13,11 +13,9 @@ import java.util.List;
|
|||
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.bytecode.enhance.spi.interceptor.LazyAttributeLoadingInterceptor;
|
||||
import org.hibernate.bytecode.spi.BytecodeEnhancementMetadata;
|
||||
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.PersistenceContext;
|
||||
|
@ -81,11 +79,6 @@ public final class Cascade {
|
|||
final EntityPersister persister,
|
||||
final Object parent,
|
||||
final T anything) throws HibernateException {
|
||||
if ( action == CascadingActions.DELETE && cascadePoint == CascadePoint.AFTER_INSERT_BEFORE_DELETE ) {
|
||||
// Before deleting an entity, ensure CollectionEntry objects for uninitialized lazy collections exist,
|
||||
// otherwise these collections are not properly deleted and this leads to FK violations
|
||||
registerUninitializedLazyCollectionEntries( eventSource, persister, parent );
|
||||
}
|
||||
if ( persister.hasCascades() || action.requiresNoCascadeChecking() ) { // performance opt
|
||||
final boolean traceEnabled = LOG.isTraceEnabled();
|
||||
if ( traceEnabled ) {
|
||||
|
@ -202,30 +195,6 @@ public final class Cascade {
|
|||
}
|
||||
}
|
||||
|
||||
private static void registerUninitializedLazyCollectionEntries(EventSource eventSource, EntityPersister persister, Object parent) {
|
||||
if ( !persister.hasCollections() || !persister.hasUninitializedLazyProperties( parent ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
final Type[] types = persister.getPropertyTypes();
|
||||
final String[] propertyNames = persister.getPropertyNames();
|
||||
final BytecodeEnhancementMetadata enhancementMetadata = persister.getBytecodeEnhancementMetadata();
|
||||
for ( int i = 0; i < types.length; i++) {
|
||||
if ( types[i].isCollectionType() && !enhancementMetadata.isAttributeLoaded( parent, propertyNames[i] ) ) {
|
||||
final CollectionType collectionType = (CollectionType) types[i];
|
||||
final CollectionPersister collectionDescriptor = persister.getFactory()
|
||||
.getRuntimeMetamodels()
|
||||
.getMappingMetamodel()
|
||||
.getCollectionDescriptor( collectionType.getRole() );
|
||||
if ( collectionDescriptor.needsRemove() || collectionDescriptor.hasCache() ) {
|
||||
final Object keyOfOwner = collectionType.getKeyOfOwner( parent, eventSource.getSession() );
|
||||
// This will make sure that a CollectionEntry exists
|
||||
collectionType.getCollection( keyOfOwner, eventSource.getSession(), parent, false );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Cascade an action to the child or children
|
||||
*/
|
||||
|
|
|
@ -12,6 +12,8 @@ import org.hibernate.LockMode;
|
|||
import org.hibernate.TransientObjectException;
|
||||
import org.hibernate.action.internal.EntityDeleteAction;
|
||||
import org.hibernate.action.internal.OrphanRemovalAction;
|
||||
import org.hibernate.bytecode.enhance.spi.LazyPropertyInitializer;
|
||||
import org.hibernate.bytecode.spi.BytecodeEnhancementMetadata;
|
||||
import org.hibernate.classic.Lifecycle;
|
||||
import org.hibernate.engine.internal.Cascade;
|
||||
import org.hibernate.engine.internal.CascadePoint;
|
||||
|
@ -32,8 +34,11 @@ import org.hibernate.internal.CoreLogging;
|
|||
import org.hibernate.internal.CoreMessageLogger;
|
||||
import org.hibernate.jpa.event.spi.CallbackRegistry;
|
||||
import org.hibernate.jpa.event.spi.CallbackRegistryConsumer;
|
||||
import org.hibernate.persister.collection.CollectionPersister;
|
||||
import org.hibernate.persister.entity.EntityPersister;
|
||||
import org.hibernate.pretty.MessageHelper;
|
||||
import org.hibernate.property.access.internal.PropertyAccessStrategyBackRefImpl;
|
||||
import org.hibernate.type.CollectionType;
|
||||
import org.hibernate.type.Type;
|
||||
import org.hibernate.type.TypeHelper;
|
||||
|
||||
|
@ -251,7 +256,7 @@ public class DefaultDeleteEventListener implements DeleteEventListener, Callback
|
|||
? persister.getValues(entity) //i.e. the entity came in from update()
|
||||
: entityEntry.getLoadedState();
|
||||
|
||||
final Object[] deletedState = createDeletedState( persister, currentState, session );
|
||||
final Object[] deletedState = createDeletedState( persister, entity, currentState, session );
|
||||
entityEntry.setDeletedState( deletedState );
|
||||
|
||||
session.getInterceptor().onDelete(
|
||||
|
@ -313,13 +318,46 @@ public class DefaultDeleteEventListener implements DeleteEventListener, Callback
|
|||
//persistenceContext.removeDatabaseSnapshot(key);
|
||||
}
|
||||
|
||||
private Object[] createDeletedState(EntityPersister persister, Object[] currentState, EventSource session) {
|
||||
Type[] propTypes = persister.getPropertyTypes();
|
||||
final Object[] deletedState = new Object[propTypes.length];
|
||||
// TypeFactory.deepCopy( currentState, propTypes, persister.getPropertyUpdateability(), deletedState, session );
|
||||
boolean[] copyability = new boolean[propTypes.length];
|
||||
java.util.Arrays.fill( copyability, true );
|
||||
TypeHelper.deepCopy( currentState, propTypes, copyability, deletedState, session );
|
||||
private Object[] createDeletedState(
|
||||
EntityPersister persister,
|
||||
Object parent,
|
||||
Object[] currentState,
|
||||
EventSource eventSource) {
|
||||
final Type[] types = persister.getPropertyTypes();
|
||||
final Object[] deletedState = new Object[types.length];
|
||||
if ( !persister.hasCollections() || !persister.hasUninitializedLazyProperties( parent ) ) {
|
||||
boolean[] copyability = new boolean[types.length];
|
||||
java.util.Arrays.fill( copyability, true );
|
||||
TypeHelper.deepCopy( currentState, types, copyability, deletedState, eventSource );
|
||||
return deletedState;
|
||||
}
|
||||
|
||||
final String[] propertyNames = persister.getPropertyNames();
|
||||
final BytecodeEnhancementMetadata enhancementMetadata = persister.getBytecodeEnhancementMetadata();
|
||||
for ( int i = 0; i < types.length; i++) {
|
||||
if ( types[i].isCollectionType() && !enhancementMetadata.isAttributeLoaded( parent, propertyNames[i] ) ) {
|
||||
final CollectionType collectionType = (CollectionType) types[i];
|
||||
final CollectionPersister collectionDescriptor = persister.getFactory()
|
||||
.getRuntimeMetamodels()
|
||||
.getMappingMetamodel()
|
||||
.getCollectionDescriptor( collectionType.getRole() );
|
||||
if ( collectionDescriptor.needsRemove() || collectionDescriptor.hasCache() ) {
|
||||
final Object keyOfOwner = collectionType.getKeyOfOwner( parent, eventSource.getSession() );
|
||||
// This will make sure that a CollectionEntry exists
|
||||
deletedState[i] = collectionType.getCollection( keyOfOwner, eventSource.getSession(), parent, false );
|
||||
}
|
||||
else {
|
||||
deletedState[i] = currentState[i];
|
||||
}
|
||||
}
|
||||
else if ( currentState[i] == LazyPropertyInitializer.UNFETCHED_PROPERTY
|
||||
|| currentState[i] == PropertyAccessStrategyBackRefImpl.UNKNOWN ) {
|
||||
deletedState[i] = currentState[i];
|
||||
}
|
||||
else {
|
||||
deletedState[i] = types[i].deepCopy( currentState[i], eventSource.getFactory() );
|
||||
}
|
||||
}
|
||||
return deletedState;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue