11
11
import org .hibernate .ReplicationMode ;
12
12
import org .hibernate .TransientObjectException ;
13
13
import org .hibernate .collection .spi .PersistentCollection ;
14
+ import org .hibernate .engine .internal .CascadePoint ;
14
15
import org .hibernate .event .spi .DeleteContext ;
15
16
import org .hibernate .event .spi .EventSource ;
16
17
import org .hibernate .event .spi .MergeContext ;
17
18
import org .hibernate .event .spi .PersistContext ;
18
19
import org .hibernate .event .spi .RefreshContext ;
19
20
import org .hibernate .internal .CoreMessageLogger ;
20
21
import org .hibernate .persister .entity .EntityPersister ;
22
+ import org .hibernate .type .AssociationType ;
21
23
import org .hibernate .type .CollectionType ;
24
+ import org .hibernate .type .ManyToOneType ;
25
+ import org .hibernate .type .OneToOneType ;
22
26
import org .hibernate .type .Type ;
23
27
import org .jboss .logging .Logger ;
24
28
@@ -395,7 +399,12 @@ public boolean anythingToCascade(EntityPersister persister) {
395
399
// with cascade NONE on all associations
396
400
// if the entity has no associations, we can just ignore it
397
401
return persister .hasToOnes ()
398
- || persister .hasOwnedCollections ();
402
+ || persister .hasOwnedCollections ()
403
+ // when hibernate.unowned_association_transient_check
404
+ // is enabled, we have to check unowned associations
405
+ || persister .hasCollections ()
406
+ && persister .getFactory ().getSessionFactoryOptions ()
407
+ .isUnownedAssociationTransientCheck ();
399
408
}
400
409
401
410
@ Override
@@ -409,6 +418,32 @@ public boolean appliesTo(Type type, CascadeStyle style) {
409
418
&& ( type .isComponentType () || type .isAssociationType () );
410
419
}
411
420
421
+ @ Override
422
+ public boolean cascadeNow (
423
+ CascadePoint cascadePoint ,
424
+ AssociationType associationType ,
425
+ SessionFactoryImplementor factory ) {
426
+ return super .cascadeNow ( cascadePoint , associationType , factory )
427
+ && ( factory .getSessionFactoryOptions ().isUnownedAssociationTransientCheck ()
428
+ || !isUnownedAssociation ( associationType , factory ) );
429
+ }
430
+
431
+ private static boolean isUnownedAssociation (AssociationType associationType , SessionFactoryImplementor factory ) {
432
+ if ( associationType instanceof ManyToOneType manyToOne ) {
433
+ // logical one-to-one + non-null unique key property name indicates unowned
434
+ return manyToOne .isLogicalOneToOne () && manyToOne .getRHSUniqueKeyPropertyName () != null ;
435
+ }
436
+ else if ( associationType instanceof OneToOneType oneToOne ) {
437
+ // constrained false + non-null unique key property name indicates unowned
438
+ return oneToOne .isNullable () && oneToOne .getRHSUniqueKeyPropertyName () != null ;
439
+ }
440
+ else if ( associationType instanceof CollectionType collectionType ) {
441
+ // for collections, we can ask the persister if we're on the inverse side
442
+ return collectionType .isInverse ( factory );
443
+ }
444
+ return false ;
445
+ }
446
+
412
447
@ Override
413
448
public boolean deleteOrphans () {
414
449
return false ;
@@ -507,6 +542,14 @@ public boolean anythingToCascade(EntityPersister persister) {
507
542
public boolean appliesTo (Type type , CascadeStyle style ) {
508
543
return style .doCascade ( this );
509
544
}
545
+
546
+ @ Override
547
+ public boolean cascadeNow (
548
+ CascadePoint cascadePoint ,
549
+ AssociationType associationType ,
550
+ SessionFactoryImplementor factory ) {
551
+ return associationType .getForeignKeyDirection ().cascadeNow ( cascadePoint );
552
+ }
510
553
}
511
554
512
555
/**
0 commit comments