From 2a70f069ad038dd096d5a0bcf275bd8fa055ceef Mon Sep 17 00:00:00 2001 From: Andrea Boriero Date: Tue, 22 Oct 2024 16:03:28 +0200 Subject: [PATCH] HHH-17838 @OneToOne relationship + @Embeddable keys + FetchType.LAZY fail --- .../internal/ToOneAttributeMapping.java | 40 ++++++++++++++----- 1 file changed, 29 insertions(+), 11 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/ToOneAttributeMapping.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/ToOneAttributeMapping.java index 2611f58fc1..3d6628cea3 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/ToOneAttributeMapping.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/ToOneAttributeMapping.java @@ -1553,7 +1553,19 @@ public class ToOneAttributeMapping having the left join we don't want to add an extra implicit join that will be translated into an SQL inner join (see HHH-15342) */ - if ( fetchTiming == FetchTiming.IMMEDIATE && selected ) { + + final ForeignKeyDescriptor.Nature resolvingKeySideOfForeignKey = creationState.getCurrentlyResolvingForeignKeyPart(); + final ForeignKeyDescriptor.Nature side; + if ( resolvingKeySideOfForeignKey == ForeignKeyDescriptor.Nature.KEY && this.sideNature == ForeignKeyDescriptor.Nature.TARGET ) { + // If we are currently resolving the key part of a foreign key we do not want to add joins. + // So if the lhs of this association is the target of the FK, we have to use the KEY part to avoid a join + side = ForeignKeyDescriptor.Nature.KEY; + } + else { + side = this.sideNature; + } + + if ( ( fetchTiming == FetchTiming.IMMEDIATE && selected ) || needsJoinFetch( side ) ) { final TableGroup tableGroup = determineTableGroupForFetch( fetchablePath, fetchParent, @@ -1631,16 +1643,6 @@ public class ToOneAttributeMapping */ - final ForeignKeyDescriptor.Nature resolvingKeySideOfForeignKey = creationState.getCurrentlyResolvingForeignKeyPart(); - final ForeignKeyDescriptor.Nature side; - if ( resolvingKeySideOfForeignKey == ForeignKeyDescriptor.Nature.KEY && this.sideNature == ForeignKeyDescriptor.Nature.TARGET ) { - // If we are currently resolving the key part of a foreign key we do not want to add joins. - // So if the lhs of this association is the target of the FK, we have to use the KEY part to avoid a join - side = ForeignKeyDescriptor.Nature.KEY; - } - else { - side = this.sideNature; - } final DomainResult keyResult; if ( side == ForeignKeyDescriptor.Nature.KEY ) { final TableGroup tableGroup = sideNature == ForeignKeyDescriptor.Nature.KEY @@ -1692,6 +1694,22 @@ public class ToOneAttributeMapping ); } + private boolean needsJoinFetch(ForeignKeyDescriptor.Nature side) { + if ( side == ForeignKeyDescriptor.Nature.TARGET ) { + // The target model part doesn't correspond to the identifier of the target entity mapping + // so we must eagerly fetch with a join (subselect would still cause problems). + final EntityIdentifierMapping identifier = entityMappingType.getIdentifierMapping(); + final ValuedModelPart targetPart = foreignKeyDescriptor.getTargetPart(); + if ( identifier != targetPart ) { + // If the identifier and the target part of the same class, we can preserve laziness as deferred loading will still work + return identifier.getExpressibleJavaType().getJavaTypeClass() != targetPart.getExpressibleJavaType() + .getJavaTypeClass(); + } + } + + return false; + } + private boolean isAffectedByEnabledFilters(DomainResultCreationState creationState) { final LoadQueryInfluencers loadQueryInfluencers = creationState.getSqlAstCreationState() .getLoadQueryInfluencers();