@@ -987,29 +987,62 @@ public void resolveInstance(Object instance, EntityInitializerData data) {
987987 setMissing ( data );
988988 }
989989 else {
990- data .setInstance ( instance );
991990 final var lazyInitializer = extractLazyInitializer ( instance );
992991 final var rowProcessingState = data .getRowProcessingState ();
993992 final var session = rowProcessingState .getSession ();
994993 final var persistenceContext = session .getPersistenceContextInternal ();
995994 if ( lazyInitializer == null ) {
996995 // Entity is most probably initialized
997- data .entityInstanceForNotify = instance ;
998996 data .concreteDescriptor = session .getEntityPersister ( null , instance );
999- resolveEntityKey ( data , data .concreteDescriptor .getIdentifier ( instance , session ) );
1000- data .entityHolder = persistenceContext .getEntityHolder ( data .entityKey );
1001- if ( data .entityHolder == null ) {
1002- // Entity was most probably removed in the same session without setting this association to null.
1003- // Since this load request can happen through `find()` which doesn't auto-flush on association joins,
1004- // the entity must be fully initialized, even if it is removed already
1005- data .entityHolder =
1006- persistenceContext .claimEntityHolderIfPossible (
1007- data .entityKey ,
1008- data .entityInstanceForNotify ,
1009- rowProcessingState .getJdbcValuesSourceProcessingState (),
1010- this
1011- );
997+ resolveEntityKey (
998+ data ,
999+ data .concreteDescriptor .getIdentifier ( instance , session )
1000+ );
1001+ data .entityHolder = persistenceContext .claimEntityHolderIfPossible (
1002+ data .entityKey ,
1003+ null ,
1004+ rowProcessingState .getJdbcValuesSourceProcessingState (),
1005+ this
1006+ );
1007+ if ( data .entityHolder .getManagedObject () == null ) {
1008+ final EntityEntry entry = persistenceContext .getEntry (
1009+ instance ); // make sure an EntityEntry exists
1010+ if ( entry == null ) {
1011+ // We cannot reuse an entity instance that has no entry in the PC,
1012+ // this can happen if the parent entity contained a detached instance.
1013+ // We need to create a new instance in this case (see resolveEntityInstance1)
1014+ instance = resolveEntityInstance ( data );
1015+ }
1016+ else {
1017+ // Entity was most probably removed in the same session without setting this association to null.
1018+ // Since this load request can happen through `find()` which doesn't auto-flush on association joins,
1019+ // the entity must be fully initialized, even if it is removed already
1020+ data .entityHolder = persistenceContext .claimEntityHolderIfPossible (
1021+ data .entityKey ,
1022+ instance ,
1023+ rowProcessingState .getJdbcValuesSourceProcessingState (),
1024+ this
1025+ );
1026+ }
1027+ }
1028+ else if ( data .entityHolder .getEntity () == null ) {
1029+ assert data .entityHolder .getProxy () != instance ;
1030+ instance = resolveEntityInstance ( data );
1031+ data .entityKey = data .entityHolder .getEntityKey ();
1032+ if ( data .entityHolder .getProxy () != null ) {
1033+ castNonNull ( extractLazyInitializer ( data .entityHolder .getProxy () ) )
1034+ .setImplementation ( instance );
1035+ }
1036+ }
1037+ else if ( data .entityHolder .getEntity () != instance ) {
1038+ // The instance contained in the parent entity is different from the managed persistent instance
1039+ // currently in the persistence context. We should always initialize the managed one in this case.
1040+ instance = data .entityHolder .getEntity ();
1041+ data .entityKey = data .entityHolder .getEntityKey ();
10121042 }
1043+
1044+ data .entityInstanceForNotify = instance ;
1045+
10131046 if ( data .concreteDescriptor .getBytecodeEnhancementMetadata ().isEnhancedForLazyLoading ()
10141047 && isPersistentAttributeInterceptable ( data .entityInstanceForNotify )
10151048 && getAttributeInterceptor ( data .entityInstanceForNotify )
@@ -1049,19 +1082,51 @@ else if ( lazyInitializer.isUninitialized() ) {
10491082 this
10501083 );
10511084 // Resolve and potentially create the entity instance
1052- data .entityInstanceForNotify = resolveEntityInstance ( data );
1053- lazyInitializer .setImplementation ( data .entityInstanceForNotify );
1054- registerLoadingEntity ( data , data .entityInstanceForNotify );
1085+ if ( data .entityHolder .getProxy () == instance ) {
1086+ data .entityInstanceForNotify = resolveEntityInstance ( data );
1087+ lazyInitializer .setImplementation ( data .entityInstanceForNotify );
1088+ }
1089+ else if ( data .entityHolder .getEntity () == null ) {
1090+ data .entityInstanceForNotify = resolveEntityInstance ( data );
1091+ if ( data .entityHolder .getProxy () != null ) {
1092+ castNonNull ( extractLazyInitializer ( data .entityHolder .getProxy () ) ).setImplementation (
1093+ data .entityInstanceForNotify );
1094+ }
1095+ }
1096+ else {
1097+ data .entityInstanceForNotify = data .entityHolder .getEntity ();
1098+ data .setState ( data .entityHolder .isInitialized () ? State .INITIALIZED : State .RESOLVED );
1099+ }
10551100 }
10561101 else {
1057- data . entityInstanceForNotify = lazyInitializer .getImplementation ();
1058- data .concreteDescriptor = session .getEntityPersister ( null , data . entityInstanceForNotify );
1102+ final var implementation = lazyInitializer .getImplementation ();
1103+ data .concreteDescriptor = session .getEntityPersister ( null , implementation );
10591104 resolveEntityKey ( data , lazyInitializer .getInternalIdentifier () );
10601105 data .entityHolder = persistenceContext .getEntityHolder ( data .entityKey );
1061- // Even though the lazyInitializer reports it is initialized, check if the entity holder reports initialized,
1062- // because in a nested initialization scenario, this nested initializer must initialize the entity
1063- data .setState ( data .entityHolder .isInitialized () ? State .INITIALIZED : State .RESOLVED );
1106+ if ( data .entityHolder .getProxy () == instance ) {
1107+ data .entityInstanceForNotify = implementation ;
1108+ // Even though the lazyInitializer reports it is initialized, check if the entity holder reports initialized,
1109+ // because in a nested initialization scenario, this nested initializer must initialize the entity
1110+ data .setState ( data .entityHolder .isInitialized () ? State .INITIALIZED : State .RESOLVED );
1111+ }
1112+ else if ( data .entityHolder .getEntity () == null ) {
1113+ data .entityInstanceForNotify = resolveEntityInstance ( data );
1114+ data .entityKey = data .entityHolder .getEntityKey ();
1115+ if ( data .entityHolder .getProxy () != null ) {
1116+ castNonNull ( extractLazyInitializer ( data .entityHolder .getProxy () ) ).setImplementation (
1117+ data .entityInstanceForNotify );
1118+ }
1119+ data .setState ( State .RESOLVED );
1120+ }
1121+ else {
1122+ data .entityInstanceForNotify = data .entityHolder .getEntity ();
1123+ data .entityKey = data .entityHolder .getEntityKey ();
1124+ data .setState ( data .entityHolder .isInitialized () ? State .INITIALIZED : State .RESOLVED );
1125+ }
10641126 }
1127+
1128+ data .setInstance ( data .entityHolder .getManagedObject () );
1129+
10651130 if ( identifierAssembler != null ) {
10661131 final Initializer <?> initializer = identifierAssembler .getInitializer ();
10671132 if ( initializer != null ) {
@@ -1478,7 +1543,7 @@ protected void initializeEntityInstance(EntityInitializerData data) {
14781543 final var entityKey = data .entityKey ;
14791544 assert entityKey != null ;
14801545
1481- final Object entityIdentifier = entityKey .getIdentifier ();
1546+ final var entityIdentifier = entityKey .getIdentifier ();
14821547 final var resolvedEntityState = extractConcreteTypeStateValues ( data );
14831548
14841549 rowProcessingState .getJdbcValuesSourceProcessingState ().registerLoadingEntityHolder ( data .entityHolder );
0 commit comments