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