HHH-9663 - Fix orphan removal cascade for one-to-one mappings.
This commit is contained in:
parent
85732409ee
commit
63e6793d8f
|
@ -26,6 +26,7 @@ import org.hibernate.internal.CoreMessageLogger;
|
||||||
import org.hibernate.persister.collection.CollectionPersister;
|
import org.hibernate.persister.collection.CollectionPersister;
|
||||||
import org.hibernate.persister.entity.EntityPersister;
|
import org.hibernate.persister.entity.EntityPersister;
|
||||||
import org.hibernate.pretty.MessageHelper;
|
import org.hibernate.pretty.MessageHelper;
|
||||||
|
import org.hibernate.proxy.HibernateProxy;
|
||||||
import org.hibernate.type.AssociationType;
|
import org.hibernate.type.AssociationType;
|
||||||
import org.hibernate.type.CollectionType;
|
import org.hibernate.type.CollectionType;
|
||||||
import org.hibernate.type.CompositeType;
|
import org.hibernate.type.CompositeType;
|
||||||
|
@ -90,9 +91,8 @@ public final class Cascade {
|
||||||
final CascadeStyle style = cascadeStyles[ i ];
|
final CascadeStyle style = cascadeStyles[ i ];
|
||||||
final String propertyName = propertyNames[ i ];
|
final String propertyName = propertyNames[ i ];
|
||||||
|
|
||||||
if ( style.doCascade( action ) ) {
|
Object child = null;
|
||||||
Object child;
|
if ( style.doCascade( action ) || action.deleteOrphans() ) {
|
||||||
|
|
||||||
if ( hasUninitializedLazyProperties &&
|
if ( hasUninitializedLazyProperties &&
|
||||||
!persister.getInstrumentationMetadata().isAttributeLoaded( parent, propertyName ) ) {
|
!persister.getInstrumentationMetadata().isAttributeLoaded( parent, propertyName ) ) {
|
||||||
// parent is a bytecode enhanced entity.
|
// parent is a bytecode enhanced entity.
|
||||||
|
@ -115,13 +115,24 @@ public final class Cascade {
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// Nothing to do, so just skip cascading to this lazy (non-collection) attribute.
|
// Nothing to do, so just skip cascading to this lazy (non-collection) attribute.
|
||||||
|
if ( action.requiresNoCascadeChecking() ) {
|
||||||
|
action.noCascade(
|
||||||
|
eventSource,
|
||||||
|
parent,
|
||||||
|
persister,
|
||||||
|
types[ i ],
|
||||||
|
i
|
||||||
|
);
|
||||||
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
child = persister.getPropertyValue( parent, i );
|
child = persister.getPropertyValue( parent, i );
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( style.doCascade( action ) ) {
|
||||||
cascadeProperty(
|
cascadeProperty(
|
||||||
action,
|
action,
|
||||||
cascadePoint,
|
cascadePoint,
|
||||||
|
@ -144,6 +155,19 @@ public final class Cascade {
|
||||||
types[ i ],
|
types[ i ],
|
||||||
i
|
i
|
||||||
);
|
);
|
||||||
|
if ( action.deleteOrphans() ) {
|
||||||
|
cascadeLogicalOneToOneOrphanRemoval(
|
||||||
|
action,
|
||||||
|
eventSource,
|
||||||
|
componentPathStackDepth,
|
||||||
|
parent,
|
||||||
|
child,
|
||||||
|
types[ i ],
|
||||||
|
style,
|
||||||
|
propertyName,
|
||||||
|
false
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -201,6 +225,29 @@ public final class Cascade {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cascadeLogicalOneToOneOrphanRemoval(
|
||||||
|
action,
|
||||||
|
eventSource,
|
||||||
|
componentPathStackDepth,
|
||||||
|
parent,
|
||||||
|
child,
|
||||||
|
type,
|
||||||
|
style,
|
||||||
|
propertyName,
|
||||||
|
isCascadeDeleteEnabled );
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void cascadeLogicalOneToOneOrphanRemoval(
|
||||||
|
final CascadingAction action,
|
||||||
|
final EventSource eventSource,
|
||||||
|
final int componentPathStackDepth,
|
||||||
|
final Object parent,
|
||||||
|
final Object child,
|
||||||
|
final Type type,
|
||||||
|
final CascadeStyle style,
|
||||||
|
final String propertyName,
|
||||||
|
final boolean isCascadeDeleteEnabled) throws HibernateException {
|
||||||
|
|
||||||
// potentially we need to handle orphan deletes for one-to-ones here...
|
// potentially we need to handle orphan deletes for one-to-ones here...
|
||||||
if ( isLogicalOneToOne( type ) ) {
|
if ( isLogicalOneToOne( type ) ) {
|
||||||
// We have a physical or logical one-to-one. See if the attribute cascade settings and action-type require
|
// We have a physical or logical one-to-one. See if the attribute cascade settings and action-type require
|
||||||
|
@ -210,7 +257,7 @@ public final class Cascade {
|
||||||
// because it is currently null.
|
// because it is currently null.
|
||||||
final EntityEntry entry = eventSource.getPersistenceContext().getEntry( parent );
|
final EntityEntry entry = eventSource.getPersistenceContext().getEntry( parent );
|
||||||
if ( entry != null && entry.getStatus() != Status.SAVING ) {
|
if ( entry != null && entry.getStatus() != Status.SAVING ) {
|
||||||
final Object loadedValue;
|
Object loadedValue;
|
||||||
if ( componentPathStackDepth == 0 ) {
|
if ( componentPathStackDepth == 0 ) {
|
||||||
// association defined on entity
|
// association defined on entity
|
||||||
loadedValue = entry.getLoadedValue( propertyName );
|
loadedValue = entry.getLoadedValue( propertyName );
|
||||||
|
@ -236,11 +283,17 @@ public final class Cascade {
|
||||||
// orphaned if the association was nulled (child == null) or receives a new value while the
|
// orphaned if the association was nulled (child == null) or receives a new value while the
|
||||||
// entity is managed (without first nulling and manually flushing).
|
// entity is managed (without first nulling and manually flushing).
|
||||||
if ( child == null || ( loadedValue != null && child != loadedValue ) ) {
|
if ( child == null || ( loadedValue != null && child != loadedValue ) ) {
|
||||||
final EntityEntry valueEntry = eventSource
|
EntityEntry valueEntry = eventSource
|
||||||
.getPersistenceContext().getEntry(
|
.getPersistenceContext().getEntry(
|
||||||
loadedValue );
|
loadedValue );
|
||||||
// Need to check this in case the context has
|
|
||||||
// already been flushed. See HHH-7829.
|
if ( valueEntry == null && loadedValue instanceof HibernateProxy ) {
|
||||||
|
// un-proxy and re-associate for cascade operation
|
||||||
|
// useful for @OneToOne defined as FetchType.LAZY
|
||||||
|
loadedValue = eventSource.getPersistenceContext().unproxyAndReassociate( loadedValue );
|
||||||
|
valueEntry = eventSource.getPersistenceContext().getEntry( loadedValue );
|
||||||
|
}
|
||||||
|
|
||||||
if ( valueEntry != null ) {
|
if ( valueEntry != null ) {
|
||||||
final String entityName = valueEntry.getPersister().getEntityName();
|
final String entityName = valueEntry.getPersister().getEntityName();
|
||||||
if ( LOG.isTraceEnabled() ) {
|
if ( LOG.isTraceEnabled() ) {
|
||||||
|
|
Loading…
Reference in New Issue