@@ -174,94 +174,102 @@ public void resolveInstance(EntityDelayedFetchInitializerData data) {
174174 concreteDescriptor = entityPersister ;
175175 }
176176
177- final PersistenceContext persistenceContext = session .getPersistenceContextInternal ();
178- if ( selectByUniqueKey ) {
179- final String uniqueKeyPropertyName = referencedModelPart .getReferencedPropertyName ();
180- final Type uniqueKeyPropertyType = ( referencedModelPart .getReferencedPropertyName () == null ) ?
181- concreteDescriptor .getIdentifierType () :
182- session .getFactory ().getRuntimeMetamodels ()
183- .getReferencedPropertyType (
184- concreteDescriptor .getEntityName (),
185- uniqueKeyPropertyName
186- );
187-
188- final EntityUniqueKey euk = new EntityUniqueKey (
189- concreteDescriptor .getEntityName (),
190- uniqueKeyPropertyName ,
191- data .entityIdentifier ,
192- uniqueKeyPropertyType ,
193- session .getFactory ()
194- );
195- Object instance = persistenceContext .getEntity ( euk );
196- if ( instance == null ) {
197- // For unique-key mappings, we always use bytecode-laziness if possible,
198- // because we can't generate a proxy based on the unique key yet
199- if ( referencedModelPart .isLazy () ) {
200- instance = UNFETCHED_PROPERTY ;
201- }
202- else {
203- // Try to load a PersistentAttributeInterceptable. If we get one, we can add the lazy
204- // field to the interceptor. If we don't get one, we load the entity by unique key.
205- PersistentAttributeInterceptable persistentAttributeInterceptable = null ;
206- if ( getParent ().isEntityInitializer () && isLazyByGraph ( rowProcessingState ) ) {
207- final Object resolvedInstance =
208- getParent ().asEntityInitializer ().getResolvedInstance ( rowProcessingState );
209- persistentAttributeInterceptable =
210- ManagedTypeHelper .asPersistentAttributeInterceptableOrNull ( resolvedInstance );
211- }
177+ initialize ( data , null , concreteDescriptor );
178+ }
179+ }
212180
213- if ( persistentAttributeInterceptable != null ) {
214- final LazyAttributeLoadingInterceptor persistentAttributeInterceptor = (LazyAttributeLoadingInterceptor ) persistentAttributeInterceptable .$$_hibernate_getInterceptor ();
215- persistentAttributeInterceptor .addLazyFieldByGraph ( navigablePath .getLocalName () );
216- instance = UNFETCHED_PROPERTY ;
217- }
218- else {
219- instance = concreteDescriptor .loadByUniqueKey (
220- uniqueKeyPropertyName ,
221- data .entityIdentifier ,
222- session
181+ protected void initialize (EntityDelayedFetchInitializerData data , @ Nullable EntityKey entityKey , EntityPersister concreteDescriptor ) {
182+ final RowProcessingState rowProcessingState = data .getRowProcessingState ();
183+ final SharedSessionContractImplementor session = rowProcessingState .getSession ();
184+ final PersistenceContext persistenceContext = session .getPersistenceContextInternal ();
185+ if ( selectByUniqueKey ) {
186+ final String uniqueKeyPropertyName = referencedModelPart .getReferencedPropertyName ();
187+ final Type uniqueKeyPropertyType = ( referencedModelPart .getReferencedPropertyName () == null ) ?
188+ concreteDescriptor .getIdentifierType () :
189+ session .getFactory ().getRuntimeMetamodels ()
190+ .getReferencedPropertyType (
191+ concreteDescriptor .getEntityName (),
192+ uniqueKeyPropertyName
223193 );
224194
225- // If the entity was not in the Persistence Context, but was found now,
226- // add it to the Persistence Context
227- if ( instance != null ) {
228- persistenceContext .addEntity ( euk , instance );
229- }
195+ final EntityUniqueKey euk = new EntityUniqueKey (
196+ concreteDescriptor .getEntityName (),
197+ uniqueKeyPropertyName ,
198+ data .entityIdentifier ,
199+ uniqueKeyPropertyType ,
200+ session .getFactory ()
201+ );
202+ Object instance = persistenceContext .getEntity ( euk );
203+ if ( instance == null ) {
204+ // For unique-key mappings, we always use bytecode-laziness if possible,
205+ // because we can't generate a proxy based on the unique key yet
206+ if ( referencedModelPart .isLazy () ) {
207+ instance = UNFETCHED_PROPERTY ;
208+ }
209+ else {
210+ // Try to load a PersistentAttributeInterceptable. If we get one, we can add the lazy
211+ // field to the interceptor. If we don't get one, we load the entity by unique key.
212+ PersistentAttributeInterceptable persistentAttributeInterceptable = null ;
213+ if ( getParent ().isEntityInitializer () && isLazyByGraph ( rowProcessingState ) ) {
214+ final Object resolvedInstance =
215+ getParent ().asEntityInitializer ().getResolvedInstance ( rowProcessingState );
216+ persistentAttributeInterceptable =
217+ ManagedTypeHelper .asPersistentAttributeInterceptableOrNull ( resolvedInstance );
218+ }
219+
220+ if ( persistentAttributeInterceptable != null ) {
221+ final LazyAttributeLoadingInterceptor persistentAttributeInterceptor = (LazyAttributeLoadingInterceptor ) persistentAttributeInterceptable .$$_hibernate_getInterceptor ();
222+ persistentAttributeInterceptor .addLazyFieldByGraph ( navigablePath .getLocalName () );
223+ instance = UNFETCHED_PROPERTY ;
224+ }
225+ else {
226+ instance = concreteDescriptor .loadByUniqueKey (
227+ uniqueKeyPropertyName ,
228+ data .entityIdentifier ,
229+ session
230+ );
231+
232+ // If the entity was not in the Persistence Context, but was found now,
233+ // add it to the Persistence Context
234+ if ( instance != null ) {
235+ persistenceContext .addEntity ( euk , instance );
230236 }
231237 }
232238 }
233- if ( instance != null ) {
234- instance = persistenceContext .proxyFor ( instance );
235- }
236- data .setInstance ( instance );
239+ }
240+ if ( instance != null ) {
241+ instance = persistenceContext .proxyFor ( instance );
242+ }
243+ data .setInstance ( instance );
244+ }
245+ else {
246+ final EntityKey ek = entityKey == null ?
247+ new EntityKey ( data .entityIdentifier , concreteDescriptor ) :
248+ entityKey ;
249+ final EntityHolder holder = persistenceContext .getEntityHolder ( ek );
250+ final Object instance ;
251+ if ( holder != null && holder .getEntity () != null ) {
252+ instance = persistenceContext .proxyFor ( holder , concreteDescriptor );
253+ }
254+ // For primary key based mappings we only use bytecode-laziness if the attribute is optional,
255+ // because the non-optionality implies that it is safe to have a proxy
256+ else if ( referencedModelPart .isOptional () && referencedModelPart .isLazy () ) {
257+ instance = UNFETCHED_PROPERTY ;
237258 }
238259 else {
239- final EntityKey entityKey = new EntityKey ( data .entityIdentifier , concreteDescriptor );
240- final EntityHolder holder = persistenceContext .getEntityHolder ( entityKey );
241- final Object instance ;
242- if ( holder != null && holder .getEntity () != null ) {
243- instance = persistenceContext .proxyFor ( holder , concreteDescriptor );
244- }
245- // For primary key based mappings we only use bytecode-laziness if the attribute is optional,
246- // because the non-optionality implies that it is safe to have a proxy
247- else if ( referencedModelPart .isOptional () && referencedModelPart .isLazy () ) {
248- instance = UNFETCHED_PROPERTY ;
249- }
250- else {
251- instance = session .internalLoad (
252- concreteDescriptor .getEntityName (),
253- data .entityIdentifier ,
254- false ,
255- false
256- );
257-
258- final LazyInitializer lazyInitializer = HibernateProxy .extractLazyInitializer ( instance );
259- if ( lazyInitializer != null ) {
260- lazyInitializer .setUnwrap ( referencedModelPart .isUnwrapProxy () && concreteDescriptor .isInstrumented () );
261- }
260+ instance = session .internalLoad (
261+ concreteDescriptor .getEntityName (),
262+ data .entityIdentifier ,
263+ false ,
264+ false
265+ );
266+
267+ final LazyInitializer lazyInitializer = HibernateProxy .extractLazyInitializer ( instance );
268+ if ( lazyInitializer != null ) {
269+ lazyInitializer .setUnwrap ( referencedModelPart .isUnwrapProxy () && concreteDescriptor .isInstrumented () );
262270 }
263- data .setInstance ( instance );
264271 }
272+ data .setInstance ( instance );
265273 }
266274 }
267275
@@ -287,9 +295,28 @@ public void resolveInstance(Object instance, EntityDelayedFetchInitializerData d
287295 // This initializer is done initializing, since this is only invoked for delayed or select initializers
288296 data .setState ( State .INITIALIZED );
289297 data .setInstance ( instance );
290- final RowProcessingState rowProcessingState = data .getRowProcessingState ();
298+ final var rowProcessingState = data .getRowProcessingState ();
299+ final var session = rowProcessingState .getSession ();
300+ final var entityDescriptor = getEntityDescriptor ();
301+ data .entityIdentifier = entityDescriptor .getIdentifier ( instance , session );
302+
303+ final var entityKey = new EntityKey ( data .entityIdentifier , entityDescriptor );
304+ final var entityHolder = session .getPersistenceContextInternal ().getEntityHolder (
305+ entityKey
306+ );
307+
308+ if ( entityHolder == null || entityHolder .getEntity () != instance && entityHolder .getProxy () != instance ) {
309+ // the existing entity instance is detached or transient
310+ if ( entityHolder != null ) {
311+ final var managed = entityHolder .getManagedObject ();
312+ data .entityIdentifier = entityHolder .getEntityKey ().getIdentifier ();
313+ data .setInstance ( managed );
314+ }
315+ else {
316+ initialize ( data , entityKey , entityDescriptor );
317+ }
318+ }
291319 if ( keyIsEager ) {
292- data .entityIdentifier = getEntityDescriptor ().getIdentifier ( instance , rowProcessingState .getSession () );
293320 final Initializer <?> initializer = identifierAssembler .getInitializer ();
294321 assert initializer != null ;
295322 initializer .resolveInstance ( data .entityIdentifier , rowProcessingState );
0 commit comments