From 0f02279f1041446b906cf75ffee9fa1cd5189739 Mon Sep 17 00:00:00 2001 From: Christian Beikov Date: Fri, 11 Feb 2022 09:31:25 +0100 Subject: [PATCH] Implement partial null key handling and respect lazy flag regardless of fetch style --- .../internal/MappingModelCreationHelper.java | 10 +++++----- .../walking/internal/FetchOptionsHelper.java | 19 +++++++++++++++++++ .../AbstractEmbeddableInitializer.java | 7 +++++++ .../JoinFormulaManyToOneLazyFetchingTest.java | 12 +++--------- .../backref/map/compkey/Mappings.hbm.xml | 2 +- .../original/UserPermissions.hbm.xml | 2 +- .../hibernate/orm/test/filter/Product.hbm.xml | 2 +- .../orm/test/jpa/fetch/Person.hbm.xml | 2 +- .../custom/basic/UserPermissions.hbm.xml | 2 +- .../declaredtype/UserPermissions.hbm.xml | 2 +- .../custom/parameterized/Mapping.hbm.xml | 2 +- .../typedmanytoone/TypedManyToOneTest.java | 4 ---- .../hibernate/orm/test/orphan/Product.hbm.xml | 2 +- migration-guide.adoc | 7 +++++++ 14 files changed, 49 insertions(+), 26 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/MappingModelCreationHelper.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/MappingModelCreationHelper.java index 2e185d1e15..fa74063e7b 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/MappingModelCreationHelper.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/MappingModelCreationHelper.java @@ -754,6 +754,7 @@ public class MappingModelCreationHelper { final FetchTiming timing = FetchOptionsHelper.determineFetchTiming( style, collectionDescriptor.getCollectionType(), + collectionDescriptor.isLazy(), sessionFactory ); @@ -1583,23 +1584,22 @@ public class MappingModelCreationHelper { final boolean lazy = value.isLazy(); if ( lazy && entityPersister.getBytecodeEnhancementMetadata().isEnhancedForLazyLoading() ) { if ( value.isUnwrapProxy() ) { - fetchTiming = FetchOptionsHelper.determineFetchTiming( fetchStyle, type, sessionFactory ); + fetchTiming = FetchOptionsHelper.determineFetchTiming( fetchStyle, type, lazy, sessionFactory ); } else if ( value instanceof ManyToOne && value.isNullable() && ( (ManyToOne) value ).isIgnoreNotFound() ) { fetchTiming = FetchTiming.IMMEDIATE; } else { - fetchTiming = FetchOptionsHelper.determineFetchTiming( fetchStyle, type, sessionFactory ); + fetchTiming = FetchOptionsHelper.determineFetchTiming( fetchStyle, type, lazy, sessionFactory ); } } - else if ( fetchStyle == FetchStyle.JOIN - || !lazy + else if ( !lazy || value instanceof OneToOne && value.isNullable() || value instanceof ManyToOne && value.isNullable() && ( (ManyToOne) value ).isIgnoreNotFound() ) { fetchTiming = FetchTiming.IMMEDIATE; } else { - fetchTiming = FetchOptionsHelper.determineFetchTiming( fetchStyle, type, sessionFactory ); + fetchTiming = FetchOptionsHelper.determineFetchTiming( fetchStyle, type, lazy, sessionFactory ); } final ToOneAttributeMapping attributeMapping = new ToOneAttributeMapping( diff --git a/hibernate-core/src/main/java/org/hibernate/persister/walking/internal/FetchOptionsHelper.java b/hibernate-core/src/main/java/org/hibernate/persister/walking/internal/FetchOptionsHelper.java index 23b89bd3d1..9544800ce7 100644 --- a/hibernate-core/src/main/java/org/hibernate/persister/walking/internal/FetchOptionsHelper.java +++ b/hibernate-core/src/main/java/org/hibernate/persister/walking/internal/FetchOptionsHelper.java @@ -126,6 +126,25 @@ public final class FetchOptionsHelper { } } + public static FetchTiming determineFetchTiming( + FetchStyle style, + AssociationType type, + boolean lazy, + SessionFactoryImplementor sessionFactory) { + switch ( style ) { + case JOIN: { + return lazy ? FetchTiming.DELAYED : FetchTiming.IMMEDIATE; + } + case BATCH: + case SUBSELECT: + default: { + return isSubsequentSelectDelayed( type, sessionFactory ) + ? FetchTiming.DELAYED + : FetchTiming.IMMEDIATE; + } + } + } + private static boolean isSubsequentSelectDelayed(AssociationType type, SessionFactoryImplementor sessionFactory) { if ( type.isAnyType() ) { // we'd need more context here. this is only kept as part of the property state on the owning entity diff --git a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/embeddable/AbstractEmbeddableInitializer.java b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/embeddable/AbstractEmbeddableInitializer.java index 7f0985e5ed..5811b50c50 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/embeddable/AbstractEmbeddableInitializer.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/embeddable/AbstractEmbeddableInitializer.java @@ -254,6 +254,8 @@ public abstract class AbstractEmbeddableInitializer extends AbstractFetchParentA private void extractRowState(RowProcessingState processingState) { stateAllNull = true; + final boolean isKey = ForeignKeyDescriptor.PART_NAME.equals( navigablePath.getLocalName() ) + || EntityIdentifierMapping.ROLE_LOCAL_NAME.equals( embedded.getFetchableName() ); for ( int i = 0; i < assemblers.size(); i++ ) { final DomainResultAssembler assembler = assemblers.get( i ); final Object contributorValue = assembler.assemble( @@ -265,6 +267,11 @@ public abstract class AbstractEmbeddableInitializer extends AbstractFetchParentA if ( contributorValue != null ) { stateAllNull = false; } + else if ( isKey ) { + // If this is a foreign key and there is a null part, the whole thing has to be turned into null + stateAllNull = true; + break; + } } applyMapsId( processingState ); diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/formula/JoinFormulaManyToOneLazyFetchingTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/formula/JoinFormulaManyToOneLazyFetchingTest.java index 69244de631..5684cdf31d 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/formula/JoinFormulaManyToOneLazyFetchingTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/formula/JoinFormulaManyToOneLazyFetchingTest.java @@ -91,15 +91,9 @@ public class JoinFormulaManyToOneLazyFetchingTest extends BaseEntityManagerFunct assertEquals( 2, stocks.size() ); assertEquals( "ABC", stocks.get( 0 ).getCode().getRefNumber() ); - try { - stocks.get( 1 ).getCode().getRefNumber(); - - fail( "Should have thrown EntityNotFoundException" ); - } - catch (EntityNotFoundException expected) { - - } - + // In 5.x, for some reason, we didn't understand that a component is a FK, + // hence a partial null was wrongly handled, but in 6.0 we handle this in a unified way + assertNull( stocks.get( 1 ).getCode() ); } ); } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/collection/backref/map/compkey/Mappings.hbm.xml b/hibernate-core/src/test/java/org/hibernate/orm/test/collection/backref/map/compkey/Mappings.hbm.xml index 3c7a60ea70..d5213464e6 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/collection/backref/map/compkey/Mappings.hbm.xml +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/collection/backref/map/compkey/Mappings.hbm.xml @@ -19,7 +19,7 @@ - + diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/collection/original/UserPermissions.hbm.xml b/hibernate-core/src/test/java/org/hibernate/orm/test/collection/original/UserPermissions.hbm.xml index cde830cc4c..93f492c66d 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/collection/original/UserPermissions.hbm.xml +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/collection/original/UserPermissions.hbm.xml @@ -29,7 +29,7 @@ - + diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/collections/custom/basic/UserPermissions.hbm.xml b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/collections/custom/basic/UserPermissions.hbm.xml index d225834939..4e75a543e2 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/collections/custom/basic/UserPermissions.hbm.xml +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/collections/custom/basic/UserPermissions.hbm.xml @@ -20,7 +20,7 @@ - +