Skip to content

Commit 8b45e29

Browse files
committed
HHH-19394 optimize cascade processing for CHECK_ON_FLUSH
1 parent 7f72e57 commit 8b45e29

File tree

9 files changed

+114
-10
lines changed

9 files changed

+114
-10
lines changed

hibernate-core/src/main/java/org/hibernate/engine/internal/Cascade.java

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ public static <T> void cascade(
8484
final EntityPersister persister,
8585
final Object parent,
8686
final T anything) throws HibernateException {
87-
if ( persister.hasCascades() || action == CHECK_ON_FLUSH ) { // performance opt
87+
if ( action.anythingToCascade( persister ) ) { // performance opt
8888
final boolean traceEnabled = LOG.isTraceEnabled();
8989
if ( traceEnabled ) {
9090
LOG.tracev( "Processing cascade {0} for: {1}", action, persister.getEntityName() );
@@ -118,7 +118,7 @@ public static <T> void cascade(
118118
&& !persister.getBytecodeEnhancementMetadata()
119119
.isAttributeLoaded( parent, propertyName );
120120

121-
if ( style.doCascade( action ) ) {
121+
if ( action.appliesTo( type, style ) ) {
122122
final Object child;
123123
if ( isUninitializedProperty ) {
124124
assert enhancedForLazyLoading;
@@ -435,8 +435,9 @@ private static <T> void cascadeComponent(
435435
for ( int i = 0; i < types.length; i++ ) {
436436
final CascadeStyle componentPropertyStyle = componentType.getCascadeStyle( i );
437437
final String subPropertyName = propertyNames[i];
438-
if ( componentPropertyStyle.doCascade( action )
439-
|| componentPropertyStyle.hasOrphanDelete() && action.deleteOrphans() ) {
438+
final Type subPropertyType = types[i];
439+
if ( action.appliesTo( subPropertyType, componentPropertyStyle )
440+
|| componentPropertyStyle.hasOrphanDelete() && action.deleteOrphans() ) {
440441
if ( children == null ) {
441442
// Get children on demand.
442443
children = componentType.getPropertyValues( child, eventSource );
@@ -448,7 +449,7 @@ private static <T> void cascadeComponent(
448449
componentPath,
449450
parent,
450451
children[i],
451-
types[i],
452+
subPropertyType,
452453
componentPropertyStyle,
453454
subPropertyName,
454455
anything,

hibernate-core/src/main/java/org/hibernate/engine/spi/CascadingAction.java

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,9 @@
88

99
import org.hibernate.HibernateException;
1010
import org.hibernate.event.spi.EventSource;
11+
import org.hibernate.persister.entity.EntityPersister;
1112
import org.hibernate.type.CollectionType;
13+
import org.hibernate.type.Type;
1214

1315
/**
1416
* A session action that may be cascaded from parent entity to its children
@@ -60,4 +62,19 @@ Iterator<?> getCascadableChildrenIterator(
6062
* Should this action be performed (or noCascade consulted) in the case of lazy properties.
6163
*/
6264
boolean performOnLazyProperty();
65+
66+
/**
67+
* Does this action have any work to do for the entity type with the given persister?
68+
*
69+
* @since 7
70+
*/
71+
boolean anythingToCascade(EntityPersister persister);
72+
73+
/**
74+
* Does this action have any work to do for fields of the given type with the given
75+
* cascade style?
76+
*
77+
* @since 7
78+
*/
79+
boolean appliesTo(Type type, CascadeStyle style);
6380
}

hibernate-core/src/main/java/org/hibernate/engine/spi/CascadingActions.java

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,9 @@
1717
import org.hibernate.event.spi.PersistContext;
1818
import org.hibernate.event.spi.RefreshContext;
1919
import org.hibernate.internal.CoreMessageLogger;
20+
import org.hibernate.persister.entity.EntityPersister;
2021
import org.hibernate.type.CollectionType;
22+
import org.hibernate.type.Type;
2123
import org.jboss.logging.Logger;
2224

2325
import java.lang.invoke.MethodHandles;
@@ -73,6 +75,11 @@ public boolean deleteOrphans() {
7375
return true;
7476
}
7577

78+
@Override
79+
public boolean anythingToCascade(EntityPersister persister) {
80+
return persister.hasCascadeDelete();
81+
}
82+
7683
@Override
7784
public String toString() {
7885
return "ACTION_DELETE";
@@ -371,6 +378,21 @@ public Iterator<?> getCascadableChildrenIterator(
371378
}
372379
}
373380

381+
@Override
382+
public boolean anythingToCascade(EntityPersister persister) {
383+
// if the entity has no associations, we can just ignore it
384+
return persister.hasToOnes()
385+
|| persister.hasOwnedCollections();
386+
}
387+
388+
@Override
389+
public boolean appliesTo(Type type, CascadeStyle style) {
390+
return super.appliesTo( type, style )
391+
// we only care about associations here,
392+
// but they can hide inside embeddables
393+
&& ( type.isComponentType() || type.isAssociationType() );
394+
}
395+
374396
@Override
375397
public boolean deleteOrphans() {
376398
return false;
@@ -457,6 +479,18 @@ public abstract static class BaseCascadingAction<T> implements CascadingAction<T
457479
public boolean performOnLazyProperty() {
458480
return true;
459481
}
482+
483+
@Override
484+
public boolean anythingToCascade(EntityPersister persister) {
485+
// if the entity has cascade NONE everywhere, we can ignore it
486+
// TODO: the persister could track which kinds of cascade it has
487+
return persister.hasCascades();
488+
}
489+
490+
@Override
491+
public boolean appliesTo(Type type, CascadeStyle style) {
492+
return style.doCascade( this );
493+
}
460494
}
461495

462496
/**

hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3745,6 +3745,11 @@ public boolean hasCascades() {
37453745
return entityMetamodel.hasCascades();
37463746
}
37473747

3748+
@Override
3749+
public boolean hasToOnes() {
3750+
return entityMetamodel.hasToOnes();
3751+
}
3752+
37483753
@Override
37493754
public boolean hasCascadeDelete() {
37503755
return entityMetamodel.hasCascadeDelete();

hibernate-core/src/main/java/org/hibernate/persister/entity/EntityPersister.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -356,6 +356,16 @@ default boolean hasCascadeDelete() {
356356
return hasCascades();
357357
}
358358

359+
/**
360+
* Determine whether this entity has any many-to-one or one-to-one associations.
361+
*
362+
* @return True if the entity has a many-to-one or one-to-one association;
363+
* false otherwise.
364+
*
365+
* @since 7
366+
*/
367+
boolean hasToOnes();
368+
359369
/**
360370
* Determine whether this entity has any owned collections.
361371
*

hibernate-core/src/main/java/org/hibernate/tuple/entity/EntityMetamodel.java

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,7 @@ public class EntityMetamodel implements Serializable {
127127

128128
private boolean lazy; //not final because proxy factory creation can fail
129129
private final boolean hasCascades;
130+
private final boolean hasToOnes;
130131
private final boolean hasCascadeDelete;
131132
private final boolean mutable;
132133
private final boolean isAbstract;
@@ -240,6 +241,7 @@ public EntityMetamodel(
240241

241242
int tempVersionProperty = NO_VERSION_INDX;
242243
boolean foundCascade = false;
244+
boolean foundToOne = false;
243245
boolean foundCascadeDelete = false;
244246
boolean foundCollection = false;
245247
boolean foundOwnedCollection = false;
@@ -380,6 +382,9 @@ else if ( !allowMutation ) {
380382
foundCascadeDelete = true;
381383
}
382384

385+
if ( indicatesToOne( attribute.getType() ) ) {
386+
foundToOne = true;
387+
}
383388
if ( indicatesCollection( attribute.getType() ) ) {
384389
foundCollection = true;
385390
}
@@ -414,6 +419,7 @@ else if ( !allowMutation ) {
414419
versionGenerator = tempVersionGenerator;
415420

416421
hasCascades = foundCascade;
422+
hasToOnes = foundToOne;
417423
hasCascadeDelete = foundCascadeDelete;
418424
hasNonIdentifierPropertyNamedId = foundNonIdentifierPropertyNamedId;
419425
versionPropertyIndex = tempVersionProperty;
@@ -621,13 +627,26 @@ public Set<String> getSubclassEntityNames() {
621627
return subclassEntityNames;
622628
}
623629

630+
private static boolean indicatesToOne(Type type) {
631+
if ( type.isEntityType() ) {
632+
return true;
633+
}
634+
else if ( type instanceof CompositeType compositeType ) {
635+
for ( Type subtype : compositeType.getSubtypes() ) {
636+
if ( indicatesToOne( subtype ) ) {
637+
return true;
638+
}
639+
}
640+
}
641+
return false;
642+
}
643+
624644
private static boolean indicatesCollection(Type type) {
625645
if ( type instanceof CollectionType ) {
626646
return true;
627647
}
628-
else if ( type.isComponentType() ) {
629-
Type[] subtypes = ( (CompositeType) type ).getSubtypes();
630-
for ( Type subtype : subtypes ) {
648+
else if ( type instanceof CompositeType compositeType ) {
649+
for ( Type subtype : compositeType.getSubtypes() ) {
631650
if ( indicatesCollection( subtype ) ) {
632651
return true;
633652
}
@@ -640,8 +659,7 @@ private static boolean indicatesOwnedCollection(Type type, MetadataImplementor m
640659
if ( type instanceof CollectionType collectionType ) {
641660
return !metadata.getCollectionBinding( collectionType.getRole() ).isInverse();
642661
}
643-
else if ( type.isComponentType() ) {
644-
final CompositeType compositeType = (CompositeType) type;
662+
else if ( type instanceof CompositeType compositeType ) {
645663
for ( Type subtype : compositeType.getSubtypes() ) {
646664
if ( indicatesOwnedCollection( subtype, metadata ) ) {
647665
return true;
@@ -742,6 +760,10 @@ public boolean hasCascades() {
742760
return hasCascades;
743761
}
744762

763+
public boolean hasToOnes() {
764+
return hasToOnes;
765+
}
766+
745767
public boolean hasCascadeDelete() {
746768
return hasCascadeDelete;
747769
}

hibernate-core/src/test/java/org/hibernate/orm/test/cfg/persister/GoofyPersisterClassProvider.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -304,6 +304,11 @@ public boolean hasCascades() {
304304
return false;
305305
}
306306

307+
@Override
308+
public boolean hasToOnes() {
309+
return false;
310+
}
311+
307312
@Override
308313
public boolean isMutable() {
309314
return false;

hibernate-core/src/test/java/org/hibernate/orm/test/jpa/ejb3configuration/PersisterClassProviderTest.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -329,6 +329,11 @@ public boolean hasCascades() {
329329
return false;
330330
}
331331

332+
@Override
333+
public boolean hasToOnes() {
334+
return false;
335+
}
336+
332337
@Override
333338
public boolean isMutable() {
334339
return false;

hibernate-core/src/test/java/org/hibernate/orm/test/legacy/CustomPersister.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,11 @@ public boolean hasCascades() {
257257
return false;
258258
}
259259

260+
@Override
261+
public boolean hasToOnes() {
262+
return false;
263+
}
264+
260265
public boolean isMutable() {
261266
return true;
262267
}

0 commit comments

Comments
 (0)