Skip to content

Commit

Permalink
HHH-14387 Alternative fix for deletion of bytecode lazy collections, …
Browse files Browse the repository at this point in the history
…by creating PersistentCollection for deletedState
  • Loading branch information
beikov committed Sep 2, 2022
1 parent 41ac1f8 commit a83ff54
Show file tree
Hide file tree
Showing 2 changed files with 46 additions and 39 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,9 @@

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;
Expand Down Expand Up @@ -81,11 +79,6 @@ public static <T> void 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 ) {
Expand Down Expand Up @@ -202,30 +195,6 @@ else if ( action.performOnLazyProperty() && type.isEntityType() ) {
}
}

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
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
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;
Expand All @@ -32,8 +34,11 @@
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;

Expand Down Expand Up @@ -251,7 +256,7 @@ protected final void deleteEntity(
? 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(
Expand Down Expand Up @@ -313,13 +318,46 @@ protected final void deleteEntity(
//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;
}

Expand Down

0 comments on commit a83ff54

Please sign in to comment.