HHH-16907 moved if from inside private method to around
This improves performance of cascadeLogicalOneToOneOrphanRemoval handling, because entity fields are only read by reflection if the field is actually a 1:1 relation (before the change, this was done every time for every field)
This commit is contained in:
parent
7c378847cb
commit
f55c017f59
|
@ -174,7 +174,7 @@ public final class Cascade {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
// If the property is uninitialized, then there cannot be any orphans.
|
// If the property is uninitialized, then there cannot be any orphans.
|
||||||
if ( action.deleteOrphans() && !isUninitializedProperty ) {
|
if ( action.deleteOrphans() && !isUninitializedProperty && isLogicalOneToOne( type ) ) {
|
||||||
cascadeLogicalOneToOneOrphanRemoval(
|
cascadeLogicalOneToOneOrphanRemoval(
|
||||||
action,
|
action,
|
||||||
eventSource,
|
eventSource,
|
||||||
|
@ -252,19 +252,21 @@ public final class Cascade {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if ( isLogicalOneToOne( type ) ) {
|
||||||
cascadeLogicalOneToOneOrphanRemoval(
|
cascadeLogicalOneToOneOrphanRemoval(
|
||||||
action,
|
action,
|
||||||
eventSource,
|
eventSource,
|
||||||
componentPath,
|
componentPath,
|
||||||
parent,
|
parent,
|
||||||
child,
|
child,
|
||||||
type,
|
type,
|
||||||
style,
|
style,
|
||||||
propertyName,
|
propertyName,
|
||||||
isCascadeDeleteEnabled );
|
isCascadeDeleteEnabled );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** potentially we need to handle orphan deletes for one-to-ones here...*/
|
||||||
private static <T> void cascadeLogicalOneToOneOrphanRemoval(
|
private static <T> void cascadeLogicalOneToOneOrphanRemoval(
|
||||||
final CascadingAction<T> action,
|
final CascadingAction<T> action,
|
||||||
final EventSource eventSource,
|
final EventSource eventSource,
|
||||||
|
@ -276,88 +278,85 @@ public final class Cascade {
|
||||||
final String propertyName,
|
final String propertyName,
|
||||||
final boolean isCascadeDeleteEnabled) throws HibernateException {
|
final boolean isCascadeDeleteEnabled) throws HibernateException {
|
||||||
|
|
||||||
// potentially we need to handle orphan deletes for one-to-ones here...
|
// We have a physical or logical one-to-one. See if the attribute cascade settings and action-type require
|
||||||
if ( isLogicalOneToOne( type ) ) {
|
// orphan checking
|
||||||
// We have a physical or logical one-to-one. See if the attribute cascade settings and action-type require
|
if ( style.hasOrphanDelete() && action.deleteOrphans() ) {
|
||||||
// orphan checking
|
// value is orphaned if loaded state for this property shows not null
|
||||||
if ( style.hasOrphanDelete() && action.deleteOrphans() ) {
|
// because it is currently null.
|
||||||
// value is orphaned if loaded state for this property shows not null
|
final PersistenceContext persistenceContext = eventSource.getPersistenceContextInternal();
|
||||||
// because it is currently null.
|
final EntityEntry entry = persistenceContext.getEntry( parent );
|
||||||
final PersistenceContext persistenceContext = eventSource.getPersistenceContextInternal();
|
if ( entry != null && entry.getStatus() != Status.SAVING ) {
|
||||||
final EntityEntry entry = persistenceContext.getEntry( parent );
|
Object loadedValue;
|
||||||
if ( entry != null && entry.getStatus() != Status.SAVING ) {
|
if ( componentPath == null ) {
|
||||||
Object loadedValue;
|
// association defined on entity
|
||||||
if ( componentPath == null ) {
|
loadedValue = entry.getLoadedValue( propertyName );
|
||||||
// association defined on entity
|
}
|
||||||
loadedValue = entry.getLoadedValue( propertyName );
|
else {
|
||||||
|
// association defined on component
|
||||||
|
// Since the loadedState in the EntityEntry is a flat domain type array
|
||||||
|
// We first have to extract the component object and then ask the component type
|
||||||
|
// recursively to give us the value of the sub-property of that object
|
||||||
|
final Type propertyType = entry.getPersister().getPropertyType( componentPath.get(0) );
|
||||||
|
if ( propertyType instanceof ComponentType ) {
|
||||||
|
loadedValue = entry.getLoadedValue( componentPath.get( 0 ) );
|
||||||
|
ComponentType componentType = (ComponentType) propertyType;
|
||||||
|
if ( componentPath.size() != 1 ) {
|
||||||
|
for ( int i = 1; i < componentPath.size(); i++ ) {
|
||||||
|
final int subPropertyIndex = componentType.getPropertyIndex( componentPath.get( i ) );
|
||||||
|
loadedValue = componentType.getPropertyValue( loadedValue, subPropertyIndex );
|
||||||
|
componentType = (ComponentType) componentType.getSubtypes()[subPropertyIndex];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
loadedValue = componentType.getPropertyValue( loadedValue, componentType.getPropertyIndex( propertyName ) );
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// association defined on component
|
// Association is probably defined in an element collection, so we can't do orphan removals
|
||||||
// Since the loadedState in the EntityEntry is a flat domain type array
|
loadedValue = null;
|
||||||
// We first have to extract the component object and then ask the component type
|
}
|
||||||
// recursively to give us the value of the sub-property of that object
|
}
|
||||||
final Type propertyType = entry.getPersister().getPropertyType( componentPath.get(0) );
|
|
||||||
if ( propertyType instanceof ComponentType ) {
|
|
||||||
loadedValue = entry.getLoadedValue( componentPath.get( 0 ) );
|
|
||||||
ComponentType componentType = (ComponentType) propertyType;
|
|
||||||
if ( componentPath.size() != 1 ) {
|
|
||||||
for ( int i = 1; i < componentPath.size(); i++ ) {
|
|
||||||
final int subPropertyIndex = componentType.getPropertyIndex( componentPath.get( i ) );
|
|
||||||
loadedValue = componentType.getPropertyValue( loadedValue, subPropertyIndex );
|
|
||||||
componentType = (ComponentType) componentType.getSubtypes()[subPropertyIndex];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
loadedValue = componentType.getPropertyValue( loadedValue, componentType.getPropertyIndex( propertyName ) );
|
// orphaned if the association was nulled (child == null) or receives a new value while the
|
||||||
}
|
// entity is managed (without first nulling and manually flushing).
|
||||||
else {
|
if ( child == null || loadedValue != null && child != loadedValue ) {
|
||||||
// Association is probably defined in an element collection, so we can't do orphan removals
|
EntityEntry valueEntry = persistenceContext.getEntry( loadedValue );
|
||||||
loadedValue = null;
|
|
||||||
|
if ( valueEntry == null && isHibernateProxy( loadedValue ) ) {
|
||||||
|
// un-proxy and re-associate for cascade operation
|
||||||
|
// useful for @OneToOne defined as FetchType.LAZY
|
||||||
|
loadedValue = persistenceContext.unproxyAndReassociate( loadedValue );
|
||||||
|
valueEntry = persistenceContext.getEntry( loadedValue );
|
||||||
|
|
||||||
|
// HHH-11965
|
||||||
|
// Should the unwrapped proxy value be equal via reference to the entity's property value
|
||||||
|
// provided by the 'child' variable, we should not trigger the orphan removal of the
|
||||||
|
// associated one-to-one.
|
||||||
|
if ( child == loadedValue ) {
|
||||||
|
// do nothing
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// orphaned if the association was nulled (child == null) or receives a new value while the
|
if ( valueEntry != null ) {
|
||||||
// entity is managed (without first nulling and manually flushing).
|
final EntityPersister persister = valueEntry.getPersister();
|
||||||
if ( child == null || loadedValue != null && child != loadedValue ) {
|
final String entityName = persister.getEntityName();
|
||||||
EntityEntry valueEntry = persistenceContext.getEntry( loadedValue );
|
if ( LOG.isTraceEnabled() ) {
|
||||||
|
LOG.tracev(
|
||||||
if ( valueEntry == null && isHibernateProxy( loadedValue ) ) {
|
"Deleting orphaned entity instance: {0}",
|
||||||
// un-proxy and re-associate for cascade operation
|
infoString( entityName, persister.getIdentifier( loadedValue, eventSource ) )
|
||||||
// useful for @OneToOne defined as FetchType.LAZY
|
);
|
||||||
loadedValue = persistenceContext.unproxyAndReassociate( loadedValue );
|
|
||||||
valueEntry = persistenceContext.getEntry( loadedValue );
|
|
||||||
|
|
||||||
// HHH-11965
|
|
||||||
// Should the unwrapped proxy value be equal via reference to the entity's property value
|
|
||||||
// provided by the 'child' variable, we should not trigger the orphan removal of the
|
|
||||||
// associated one-to-one.
|
|
||||||
if ( child == loadedValue ) {
|
|
||||||
// do nothing
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( valueEntry != null ) {
|
if ( type.isAssociationType()
|
||||||
final EntityPersister persister = valueEntry.getPersister();
|
&& ( (AssociationType) type ).getForeignKeyDirection().equals(TO_PARENT) ) {
|
||||||
final String entityName = persister.getEntityName();
|
// If FK direction is to-parent, we must remove the orphan *before* the queued update(s)
|
||||||
if ( LOG.isTraceEnabled() ) {
|
// occur. Otherwise, replacing the association on a managed entity, without manually
|
||||||
LOG.tracev(
|
// nulling and flushing, causes FK constraint violations.
|
||||||
"Deleting orphaned entity instance: {0}",
|
eventSource.removeOrphanBeforeUpdates( entityName, loadedValue );
|
||||||
infoString( entityName, persister.getIdentifier( loadedValue, eventSource ) )
|
}
|
||||||
);
|
else {
|
||||||
}
|
// Else, we must delete after the updates.
|
||||||
|
eventSource.delete( entityName, loadedValue, isCascadeDeleteEnabled, DeleteContext.create() );
|
||||||
if ( type.isAssociationType()
|
|
||||||
&& ( (AssociationType) type ).getForeignKeyDirection().equals(TO_PARENT) ) {
|
|
||||||
// If FK direction is to-parent, we must remove the orphan *before* the queued update(s)
|
|
||||||
// occur. Otherwise, replacing the association on a managed entity, without manually
|
|
||||||
// nulling and flushing, causes FK constraint violations.
|
|
||||||
eventSource.removeOrphanBeforeUpdates( entityName, loadedValue );
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// Else, we must delete after the updates.
|
|
||||||
eventSource.delete( entityName, loadedValue, isCascadeDeleteEnabled, DeleteContext.create() );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue