diff --git a/hibernate-core/src/main/java/org/hibernate/DotIdentifierSequence.java b/hibernate-core/src/main/java/org/hibernate/DotIdentifierSequence.java index b668c27b78..891a2fe05b 100644 --- a/hibernate-core/src/main/java/org/hibernate/DotIdentifierSequence.java +++ b/hibernate-core/src/main/java/org/hibernate/DotIdentifierSequence.java @@ -6,6 +6,8 @@ */ package org.hibernate; +import java.util.function.BiFunction; + /** * Hibernate often deals with compound names/paths. This interface defines a standard way of interacting with them * @@ -21,4 +23,15 @@ public interface DotIdentifierSequence { default boolean isRoot() { return getParent() == null; } + + default T resolve(T base, BiFunction resolver) { + final T result; + if ( getParent() == null ) { + result = base; + } + else { + result = resolver.apply( getParent().resolve( base, resolver ), getLocalName() ); + } + return result; + } } diff --git a/hibernate-core/src/main/java/org/hibernate/boot/query/HbmResultSetMappingDescriptor.java b/hibernate-core/src/main/java/org/hibernate/boot/query/HbmResultSetMappingDescriptor.java index c68a8a2089..7eb895ba56 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/query/HbmResultSetMappingDescriptor.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/query/HbmResultSetMappingDescriptor.java @@ -26,11 +26,14 @@ import org.hibernate.boot.jaxb.hbm.spi.JaxbHbmNativeQueryScalarReturnType; import org.hibernate.boot.jaxb.hbm.spi.JaxbHbmResultSetMappingType; import org.hibernate.boot.spi.MetadataBuildingContext; import org.hibernate.internal.util.collections.CollectionHelper; +import org.hibernate.metamodel.mapping.BasicValuedModelPart; import org.hibernate.metamodel.mapping.EntityDiscriminatorMapping; import org.hibernate.metamodel.mapping.EntityMappingType; +import org.hibernate.metamodel.mapping.ModelPart; import org.hibernate.metamodel.mapping.PluralAttributeMapping; import org.hibernate.persister.collection.CollectionPersister; import org.hibernate.query.NavigablePath; +import org.hibernate.query.internal.FetchMementoBasicStandard; import org.hibernate.query.internal.FetchMementoHbmStandard; import org.hibernate.query.internal.FetchMementoHbmStandard.FetchParentMemento; import org.hibernate.query.internal.ModelPartResultMementoBasicImpl; @@ -538,9 +541,10 @@ public class HbmResultSetMappingDescriptor implements NamedResultSetMappingDescr ); } navigablePath = fetchParentMemento.getNavigablePath().append( propertyPathParts[ i ] ); + fetchable = (Fetchable) ( (FetchableContainer) fetchable ).findSubPart( propertyPathParts[i], null ); } - return new FetchMementoHbmStandard( navigablePath, fetchParentMemento, fetchable ); + return new FetchMementoBasicStandard( navigablePath, (BasicValuedModelPart) fetchable, columnAliases.get( 0 ) ); } @Override diff --git a/hibernate-core/src/main/java/org/hibernate/boot/query/SqlResultSetMappingDescriptor.java b/hibernate-core/src/main/java/org/hibernate/boot/query/SqlResultSetMappingDescriptor.java index 35c448f4a4..5f02ce07cf 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/query/SqlResultSetMappingDescriptor.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/query/SqlResultSetMappingDescriptor.java @@ -28,7 +28,7 @@ import org.hibernate.metamodel.mapping.EntityDiscriminatorMapping; import org.hibernate.metamodel.mapping.EntityMappingType; import org.hibernate.metamodel.mapping.ModelPart; import org.hibernate.query.NavigablePath; -import org.hibernate.query.internal.FetchMementoJpa; +import org.hibernate.query.internal.FetchMementoBasicStandard; import org.hibernate.query.internal.ModelPartResultMementoBasicImpl; import org.hibernate.query.internal.NamedResultSetMappingMementoImpl; import org.hibernate.query.internal.ResultMementoBasicStandard; @@ -41,6 +41,7 @@ import org.hibernate.query.named.NamedResultSetMappingMemento; import org.hibernate.query.named.ResultMemento; import org.hibernate.query.named.ResultMementoBasic; import org.hibernate.query.named.ResultMementoInstantiation.ArgumentMemento; +import org.hibernate.query.results.complete.CompleteResultBuilderBasicModelPart; import org.hibernate.type.descriptor.java.JavaTypeDescriptor; /** @@ -395,7 +396,20 @@ public class SqlResultSetMappingDescriptor implements NamedResultSetMappingDescr @Override public FetchMemento resolve(ResultSetMappingResolutionContext resolutionContext) { - return new FetchMementoJpa( navigablePath, relativeFetchPath ); + final RuntimeMetamodels runtimeMetamodels = resolutionContext.getSessionFactory().getRuntimeMetamodels(); + final EntityMappingType entityMapping = runtimeMetamodels.getEntityMappingType( entityName ); + + final ModelPart subPart = entityMapping.resolveSubPart( navigablePath ); + if ( subPart instanceof BasicValuedModelPart ) { + assert columnNames.size() == 1; + final BasicValuedModelPart basicPart = (BasicValuedModelPart) subPart; + + return new FetchMementoBasicStandard( navigablePath, basicPart, columnNames.get( 0 ) ); + } + throw new NotYetImplementedFor6Exception( + "Only support for basic-valued model-parts have been implemented : " + relativeFetchPath + + " [" + subPart + "]" + ); } } } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/Queryable.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/Queryable.java index bede4c3506..6361a7b17d 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/Queryable.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/Queryable.java @@ -8,6 +8,7 @@ package org.hibernate.metamodel.mapping; import java.util.function.Consumer; +import org.hibernate.DotIdentifierSequence; import org.hibernate.boot.spi.SessionFactoryOptions; /** @@ -33,6 +34,10 @@ public interface Queryable extends ModelPart { */ ModelPart findSubPart(String name, EntityMappingType treatTargetType); + default ModelPart resolveSubPart(DotIdentifierSequence path) { + return path.resolve( (ModelPart) this, (part, name) -> ( (Queryable) part ).findSubPart( name, null ) ); + } + /** * For an entity, this form allows for Hibernate's "implicit treat" support - * meaning it should find a sub-part whether defined on the entity or one of its sub-types. diff --git a/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java b/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java index 733525a314..1a923346b6 100644 --- a/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java +++ b/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java @@ -219,6 +219,7 @@ import org.hibernate.sql.ast.tree.predicate.Predicate; import org.hibernate.sql.results.graph.DomainResult; import org.hibernate.sql.results.graph.DomainResultCreationState; import org.hibernate.sql.results.graph.Fetchable; +import org.hibernate.sql.results.graph.FetchableContainer; import org.hibernate.sql.results.graph.entity.internal.EntityResultImpl; import org.hibernate.stat.spi.StatisticsImplementor; import org.hibernate.tuple.GenerationTiming; @@ -6751,11 +6752,14 @@ public abstract class AbstractEntityPersister public void visitKeyFetchables( Consumer fetchableConsumer, EntityMappingType treatTargetType) { -// if ( getIdentifierMapping() instanceof FetchableContainer ) { +// final EntityIdentifierMapping identifierMapping = getIdentifierMapping(); +// if ( identifierMapping instanceof FetchableContainer ) { // // essentially means the entity has a composite id - ask the embeddable to visit its fetchables -// ( (FetchableContainer) getIdentifierMapping() ).visitFetchables( fetchableConsumer, treatTargetType ); +// ( (FetchableContainer) identifierMapping ).visitFetchables( fetchableConsumer, treatTargetType ); +// } +// else { +// fetchableConsumer.accept( (Fetchable) identifierMapping ); // } - // otherwise, nothing to do } @Override diff --git a/hibernate-core/src/main/java/org/hibernate/query/internal/FetchBuilderJpa.java b/hibernate-core/src/main/java/org/hibernate/query/internal/FetchBuilderJpa.java deleted file mode 100644 index febdd88d4a..0000000000 --- a/hibernate-core/src/main/java/org/hibernate/query/internal/FetchBuilderJpa.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Hibernate, Relational Persistence for Idiomatic Java - * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later - * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html - */ -package org.hibernate.query.internal; - -import java.util.function.BiFunction; - -import org.hibernate.LockMode; -import org.hibernate.engine.FetchTiming; -import org.hibernate.metamodel.mapping.ModelPart; -import org.hibernate.query.NavigablePath; -import org.hibernate.query.results.FetchBuilder; -import org.hibernate.query.results.dynamic.DynamicFetchBuilderLegacy; -import org.hibernate.sql.results.graph.DomainResultCreationState; -import org.hibernate.sql.results.graph.Fetch; -import org.hibernate.sql.results.graph.FetchParent; -import org.hibernate.sql.results.graph.Fetchable; -import org.hibernate.sql.results.graph.FetchableContainer; -import org.hibernate.sql.results.jdbc.spi.JdbcValuesMetadata; - -/** - * @author Steve Ebersole - */ -public class FetchBuilderJpa implements FetchBuilder { - private final NavigablePath navigablePath; - private final String attributePath; - - public FetchBuilderJpa(NavigablePath navigablePath, String attributePath) { - this.navigablePath = navigablePath; - this.attributePath = attributePath; - } - - @Override - public Fetch buildFetch( - FetchParent parent, - NavigablePath fetchPath, - JdbcValuesMetadata jdbcResultsMetadata, - BiFunction legacyFetchResolver, - DomainResultCreationState domainResultCreationState) { - assert fetchPath.equals( navigablePath ); - assert fetchPath.getFullPath().endsWith( attributePath ); - - final FetchableContainer container = parent.getReferencedMappingContainer(); - final Fetchable subPart = (Fetchable) container.findSubPart( fetchPath.getLocalName(), null ); - return subPart.generateFetch( - parent, - fetchPath, - FetchTiming.IMMEDIATE, - true, - LockMode.READ, - null, - domainResultCreationState - ); - } -} diff --git a/hibernate-core/src/main/java/org/hibernate/query/internal/FetchMementoJpa.java b/hibernate-core/src/main/java/org/hibernate/query/internal/FetchMementoJpa.java deleted file mode 100644 index 67cb4ae10f..0000000000 --- a/hibernate-core/src/main/java/org/hibernate/query/internal/FetchMementoJpa.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Hibernate, Relational Persistence for Idiomatic Java - * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later - * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html - */ -package org.hibernate.query.internal; - -import java.util.function.Consumer; - -import org.hibernate.query.NavigablePath; -import org.hibernate.query.named.FetchMemento; -import org.hibernate.query.results.FetchBuilder; - -/** - * @author Steve Ebersole - */ -public class FetchMementoJpa implements FetchMemento { - - private final NavigablePath fetchPath; - private final String attributePath; - - public FetchMementoJpa(NavigablePath fetchPath, String attributePath) { - this.fetchPath = fetchPath; - this.attributePath = attributePath; - } - - @Override - public FetchBuilder resolve( - Parent parent, - Consumer querySpaceConsumer, - ResultSetMappingResolutionContext context) { - final String[] names = attributePath.split( "\\." ); - - NavigablePath fetchPath = parent.getNavigablePath(); - //noinspection ForLoopReplaceableByForEach - for ( int i = 0; i < names.length; i++ ) { - fetchPath = fetchPath.append( names[ i ] ); - } - - return new FetchBuilderJpa( fetchPath, attributePath ); - } - - @Override - public NavigablePath getNavigablePath() { - return fetchPath; - } - -} diff --git a/hibernate-core/src/main/java/org/hibernate/query/results/Builders.java b/hibernate-core/src/main/java/org/hibernate/query/results/Builders.java index c6179464b9..aaf4282b12 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/results/Builders.java +++ b/hibernate-core/src/main/java/org/hibernate/query/results/Builders.java @@ -34,6 +34,7 @@ import org.hibernate.query.results.implicit.ImplicitFetchBuilder; import org.hibernate.query.results.implicit.ImplicitFetchBuilderBasic; import org.hibernate.query.results.implicit.ImplicitFetchBuilderEmbeddable; import org.hibernate.query.results.implicit.ImplicitModelPartResultBuilderEntity; +import org.hibernate.sql.results.graph.DomainResultCreationState; import org.hibernate.sql.results.graph.Fetchable; import org.hibernate.sql.results.graph.embeddable.EmbeddableValuedFetchable; import org.hibernate.sql.results.graph.entity.EntityValuedFetchable; @@ -243,7 +244,10 @@ public class Builders { return new ImplicitModelPartResultBuilderEntity( entityMappingType ); } - public static ImplicitFetchBuilder implicitFetchBuilder(NavigablePath fetchPath, Fetchable fetchable) { + public static ImplicitFetchBuilder implicitFetchBuilder( + NavigablePath fetchPath, + Fetchable fetchable, + DomainResultCreationState creationState) { if ( fetchable instanceof BasicValuedModelPart ) { final BasicValuedModelPart basicValuedFetchable = (BasicValuedModelPart) fetchable; return new ImplicitFetchBuilderBasic( fetchPath, basicValuedFetchable ); @@ -251,7 +255,7 @@ public class Builders { if ( fetchable instanceof EmbeddableValuedFetchable ) { final EmbeddableValuedFetchable embeddableValuedFetchable = (EmbeddableValuedFetchable) fetchable; - return new ImplicitFetchBuilderEmbeddable( fetchPath, embeddableValuedFetchable ); + return new ImplicitFetchBuilderEmbeddable( fetchPath, embeddableValuedFetchable, creationState ); } if ( fetchable instanceof EntityValuedFetchable ) { diff --git a/hibernate-core/src/main/java/org/hibernate/query/results/DomainResultCreationStateImpl.java b/hibernate-core/src/main/java/org/hibernate/query/results/DomainResultCreationStateImpl.java index 51e417ac47..a8af2d09c5 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/results/DomainResultCreationStateImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/query/results/DomainResultCreationStateImpl.java @@ -20,7 +20,9 @@ import org.hibernate.internal.util.collections.Stack; import org.hibernate.internal.util.collections.StandardStack; import org.hibernate.metamodel.mapping.AssociationKey; import org.hibernate.metamodel.mapping.EntityIdentifierMapping; +import org.hibernate.metamodel.mapping.EntityValuedModelPart; import org.hibernate.metamodel.mapping.ModelPart; +import org.hibernate.metamodel.mapping.internal.NonAggregatedIdentifierMappingImpl; import org.hibernate.query.EntityIdentifierNavigablePath; import org.hibernate.query.NavigablePath; import org.hibernate.query.results.dynamic.DynamicFetchBuilderLegacy; @@ -39,7 +41,9 @@ import org.hibernate.sql.results.ResultsLogger; import org.hibernate.sql.results.graph.DomainResultCreationState; import org.hibernate.sql.results.graph.Fetch; import org.hibernate.sql.results.graph.FetchParent; +import org.hibernate.sql.results.graph.Fetchable; import org.hibernate.sql.results.graph.FetchableContainer; +import org.hibernate.sql.results.graph.embeddable.EmbeddableValuedFetchable; import org.hibernate.sql.results.graph.entity.EntityValuedFetchable; import org.hibernate.sql.results.jdbc.spi.JdbcValuesMetadata; import org.hibernate.type.descriptor.java.JavaTypeDescriptor; @@ -113,10 +117,18 @@ public class DomainResultCreationStateImpl return jdbcResultsMetadata; } + public NavigablePath getCurrentRelativePath() { + return relativePathStack.getCurrent(); + } + public void pushExplicitFetchMementoResolver(Function resolver) { fetchBuilderResolverStack.push( resolver ); } + public Function getCurrentExplicitFetchMementoResolver() { + return fetchBuilderResolverStack.getCurrent(); + } + public Function popExplicitFetchMementoResolver() { return fetchBuilderResolverStack.pop(); } @@ -299,75 +311,71 @@ public class DomainResultCreationStateImpl final List fetches = CollectionHelper.arrayList( fetchableContainer.getNumberOfFetchables() ); + final Consumer fetchableConsumer = fetchable -> { + final String fetchableName = fetchable.getFetchableName(); + final NavigablePath fetchPath = fetchParent.getNavigablePath().append( fetchableName ); + final NavigablePath relativePath = relativePathStack.isEmpty() + ? new NavigablePath( fetchableName ) + : relativePathStack.getCurrent().append( fetchableName ); + + relativePathStack.push( relativePath ); + try { + final FetchBuilder explicitFetchBuilder = fetchBuilderResolverStack + .getCurrent() + .apply( relativePath.getFullPath() ); + final FetchBuilder fetchBuilder = explicitFetchBuilder != null + ? explicitFetchBuilder + : Builders.implicitFetchBuilder( fetchPath, fetchable, this ); + final Fetch fetch = fetchBuilder.buildFetch( + fetchParent, + fetchPath, + jdbcResultsMetadata, + (s, s2) -> { + throw new UnsupportedOperationException(); + }, + this + ); + fetches.add( fetch ); + } + finally { + relativePathStack.pop(); + } + }; + boolean previous = this.processingKeyFetches; this.processingKeyFetches = true; - if ( fetchableContainer instanceof EntityValuedFetchable ) { - final EntityValuedFetchable entityValuedFetchable = (EntityValuedFetchable) fetchableContainer; + if ( fetchableContainer instanceof EntityValuedModelPart ) { + final EntityValuedModelPart entityValuedFetchable = (EntityValuedModelPart) fetchableContainer; final EntityIdentifierMapping identifierMapping = entityValuedFetchable.getEntityMappingType().getIdentifierMapping(); - relativePathStack.push( - new EntityIdentifierNavigablePath( - relativePathStack.getCurrent(), - attributeName( identifierMapping ) - ) - ); + final boolean idClass = identifierMapping instanceof NonAggregatedIdentifierMappingImpl; + if ( idClass ) { + relativePathStack.push( + new EntityIdentifierNavigablePath( + relativePathStack.getCurrent(), + attributeName( identifierMapping ) + ) + ); + } try { - entityValuedFetchable.getEntityMappingType().visitKeyFetchables( - fetchable -> { - // depends whether these fetchables are the identifier mapping or - // the identifier sub-attribuates (if composite) - final String fetchableName = fetchable.getFetchableName(); - final NavigablePath fetchPath = fetchParent.getNavigablePath().append( fetchableName ); - final NavigablePath relativePath = relativePathStack.isEmpty() - ? new NavigablePath( fetchableName ) - : relativePathStack.getCurrent().append( fetchableName ); - }, - null - ); + if ( identifierMapping instanceof FetchableContainer ) { + // essentially means the entity has a composite id - ask the embeddable to visit its fetchables + ( (FetchableContainer) identifierMapping ).visitFetchables( fetchableConsumer, null ); + } + else { + fetchableConsumer.accept( (Fetchable) identifierMapping ); + } } finally { this.processingKeyFetches = previous; - this.relativePathStack.pop(); + if ( idClass ) { + this.relativePathStack.pop(); + } } } - - - fetchableContainer.visitFetchables( - fetchable -> { - final String fetchableName = fetchable.getFetchableName(); - final NavigablePath fetchPath = fetchParent.getNavigablePath().append( fetchableName ); - final NavigablePath relativePath = relativePathStack.isEmpty() - ? new NavigablePath( fetchableName ) - : relativePathStack.getCurrent().append( fetchableName ); - - relativePathStack.push( relativePath ); - try { - final FetchBuilder explicitFetchBuilder = fetchBuilderResolverStack - .getCurrent() - .apply( relativePath.getFullPath() ); - final FetchBuilder fetchBuilder = explicitFetchBuilder != null - ? explicitFetchBuilder - : Builders.implicitFetchBuilder( fetchPath, fetchable ); - - final Fetch fetch = fetchBuilder.buildFetch( - fetchParent, - fetchPath, - jdbcResultsMetadata, - (s, s2) -> { - throw new UnsupportedOperationException(); - }, - this - ); - fetches.add( fetch ); - } - finally { - relativePathStack.pop(); - } - }, - null - ); + fetchableContainer.visitFetchables( fetchableConsumer, null ); return fetches; } diff --git a/hibernate-core/src/main/java/org/hibernate/query/results/complete/CompleteResultBuilderEntityStandard.java b/hibernate-core/src/main/java/org/hibernate/query/results/complete/CompleteResultBuilderEntityStandard.java index 91de85af26..227a99da79 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/results/complete/CompleteResultBuilderEntityStandard.java +++ b/hibernate-core/src/main/java/org/hibernate/query/results/complete/CompleteResultBuilderEntityStandard.java @@ -30,19 +30,19 @@ public class CompleteResultBuilderEntityStandard implements CompleteResultBuilde private final EntityMappingType entityDescriptor; private final LockMode lockMode; private final ResultBuilderBasicValued discriminatorResultBuilder; - private final HashMap fetchBuilderMap; + private final HashMap explicitFetchBuilderMap; public CompleteResultBuilderEntityStandard( NavigablePath navigablePath, EntityMappingType entityDescriptor, LockMode lockMode, ResultBuilderBasicValued discriminatorResultBuilder, - HashMap fetchBuilderMap) { + HashMap explicitFetchBuilderMap) { this.navigablePath = navigablePath; this.entityDescriptor = entityDescriptor; this.lockMode = lockMode; this.discriminatorResultBuilder = discriminatorResultBuilder; - this.fetchBuilderMap = fetchBuilderMap; + this.explicitFetchBuilderMap = explicitFetchBuilderMap; } @Override @@ -62,41 +62,49 @@ public class CompleteResultBuilderEntityStandard implements CompleteResultBuilde BiFunction legacyFetchResolver, DomainResultCreationState domainResultCreationState) { final DomainResultCreationStateImpl impl = ResultsHelper.impl( domainResultCreationState ); + impl.disallowPositionalSelections(); - // we just want it added to the registry - impl.getFromClauseAccess().resolveTableGroup( - navigablePath, - np -> entityDescriptor.createRootTableGroup( - navigablePath, - null, - false, - lockMode, - () -> predicate -> {}, - impl, - impl.getCreationContext() - ) - ); + impl.pushExplicitFetchMementoResolver( explicitFetchBuilderMap::get ); - final BasicResult discriminatorResult; - if ( discriminatorResultBuilder != null ) { - discriminatorResult = discriminatorResultBuilder.buildResult( - jdbcResultsMetadata, - resultPosition, - legacyFetchResolver, + try { + // we just want it added to the registry + impl.getFromClauseAccess().resolveTableGroup( + navigablePath, + np -> entityDescriptor.createRootTableGroup( + navigablePath, + null, + false, + lockMode, + () -> predicate -> {}, + impl, + impl.getCreationContext() + ) + ); + + final BasicResult discriminatorResult; + if ( discriminatorResultBuilder != null ) { + discriminatorResult = discriminatorResultBuilder.buildResult( + jdbcResultsMetadata, + resultPosition, + legacyFetchResolver, + domainResultCreationState + ); + } + else { + discriminatorResult = null; + } + + return new EntityResultImpl( + navigablePath, + entityDescriptor, + null, + lockMode, + discriminatorResult, domainResultCreationState ); } - else { - discriminatorResult = null; + finally { + impl.popExplicitFetchMementoResolver(); } - - return new EntityResultImpl( - navigablePath, - entityDescriptor, - null, - lockMode, - discriminatorResult, - domainResultCreationState - ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/results/implicit/ImplicitFetchBuilderBasic.java b/hibernate-core/src/main/java/org/hibernate/query/results/implicit/ImplicitFetchBuilderBasic.java index bff97b4624..ec762d2c0c 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/results/implicit/ImplicitFetchBuilderBasic.java +++ b/hibernate-core/src/main/java/org/hibernate/query/results/implicit/ImplicitFetchBuilderBasic.java @@ -11,6 +11,7 @@ import java.util.function.BiFunction; import org.hibernate.engine.FetchTiming; import org.hibernate.metamodel.mapping.BasicValuedModelPart; import org.hibernate.metamodel.mapping.ConvertibleModelPart; +import org.hibernate.metamodel.model.convert.spi.BasicValueConverter; import org.hibernate.query.NavigablePath; import org.hibernate.query.results.DomainResultCreationStateImpl; import org.hibernate.query.results.ResultsHelper; @@ -71,6 +72,14 @@ public class ImplicitFetchBuilderBasic implements ImplicitFetchBuilder { .getTypeConfiguration() ); + final BasicValueConverter valueConverter; + if ( fetchable instanceof ConvertibleModelPart ) { + valueConverter = ( (ConvertibleModelPart) fetchable ).getValueConverter(); + } + else { + valueConverter = null; + } + return new BasicFetch<>( valuesArrayPosition, parent, @@ -78,7 +87,7 @@ public class ImplicitFetchBuilderBasic implements ImplicitFetchBuilder { fetchable, // todo (6.0) - we don't know true, - ( (ConvertibleModelPart) fetchable ).getValueConverter(), + valueConverter, FetchTiming.IMMEDIATE, domainResultCreationState ); diff --git a/hibernate-core/src/main/java/org/hibernate/query/results/implicit/ImplicitFetchBuilderEmbeddable.java b/hibernate-core/src/main/java/org/hibernate/query/results/implicit/ImplicitFetchBuilderEmbeddable.java index 09b3c3ad0b..82f74906e1 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/results/implicit/ImplicitFetchBuilderEmbeddable.java +++ b/hibernate-core/src/main/java/org/hibernate/query/results/implicit/ImplicitFetchBuilderEmbeddable.java @@ -6,12 +6,17 @@ */ package org.hibernate.query.results.implicit; +import java.util.LinkedHashMap; +import java.util.Map; import java.util.function.BiFunction; +import java.util.function.Function; import org.hibernate.LockMode; import org.hibernate.engine.FetchTiming; import org.hibernate.query.NavigablePath; +import org.hibernate.query.results.Builders; import org.hibernate.query.results.DomainResultCreationStateImpl; +import org.hibernate.query.results.FetchBuilder; import org.hibernate.query.results.SqlSelectionImpl; import org.hibernate.query.results.dynamic.DynamicFetchBuilderLegacy; import org.hibernate.sql.ast.SqlAstJoinType; @@ -35,12 +40,36 @@ import static org.hibernate.sql.ast.spi.SqlExpressionResolver.createColumnRefere public class ImplicitFetchBuilderEmbeddable implements ImplicitFetchBuilder { private final NavigablePath fetchPath; private final EmbeddableValuedFetchable fetchable; + private final Map fetchBuilders; public ImplicitFetchBuilderEmbeddable( NavigablePath fetchPath, - EmbeddableValuedFetchable fetchable) { + EmbeddableValuedFetchable fetchable, + DomainResultCreationState creationState) { this.fetchPath = fetchPath; this.fetchable = fetchable; + final DomainResultCreationStateImpl creationStateImpl = impl( creationState ); + final NavigablePath relativePath = creationStateImpl.getCurrentRelativePath(); + final Function fetchBuilderResolver = creationStateImpl.getCurrentExplicitFetchMementoResolver(); + final Map fetchBuilders = new LinkedHashMap<>( fetchable.getNumberOfFetchables() ); + fetchable.visitFetchables( + subFetchable -> { + final NavigablePath subFetchPath = relativePath.append( subFetchable.getFetchableName() ); + final FetchBuilder explicitFetchBuilder = fetchBuilderResolver + .apply( subFetchPath.getFullPath() ); + if ( explicitFetchBuilder == null ) { + fetchBuilders.put( + subFetchPath, + Builders.implicitFetchBuilder( fetchPath, subFetchable, creationStateImpl ) + ); + } + else { + fetchBuilders.put( subFetchPath, explicitFetchBuilder ); + } + }, + null + ); + this.fetchBuilders = fetchBuilders; } @Override @@ -70,30 +99,7 @@ public class ImplicitFetchBuilderEmbeddable implements ImplicitFetchBuilder { } ); - fetchable.forEachSelection( - (columnIndex, selection) -> { - final TableReference tableReference = tableGroup.getTableReference( selection.getContainingTableExpression() ); - - final int jdbcPosition = jdbcResultsMetadata.resolveColumnPosition( selection.getSelectionExpression() ); - final int valuesArrayPosition = jdbcPositionToValuesArrayPosition( jdbcPosition ); - - final Expression expression = creationStateImpl.resolveSqlExpression( - createColumnReferenceKey( tableReference, selection.getSelectionExpression() ), - processingState -> new SqlSelectionImpl( - valuesArrayPosition, - selection.getJdbcMapping() - ) - ); - - creationStateImpl.resolveSqlSelection( - expression, - selection.getJdbcMapping().getJavaTypeDescriptor(), - creationStateImpl.getSessionFactory().getTypeConfiguration() - ); - } - ); - - return fetchable.generateFetch( + final Fetch fetch = fetchable.generateFetch( parent, fetchPath, FetchTiming.IMMEDIATE, @@ -102,6 +108,18 @@ public class ImplicitFetchBuilderEmbeddable implements ImplicitFetchBuilder { null, creationState ); + final FetchParent fetchParent = (FetchParent) fetch; + fetchBuilders.forEach( + (subFetchPath, fetchBuilder) -> fetchBuilder.buildFetch( + fetchParent, + subFetchPath, + jdbcResultsMetadata, + legacyFetchResolver, + creationState + ) + ); + + return fetch; } @Override diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/query/resultmapping/EntityResultTests.java b/hibernate-core/src/test/java/org/hibernate/orm/test/query/resultmapping/EntityResultTests.java index f15d9e3cda..71bf57b5d4 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/query/resultmapping/EntityResultTests.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/query/resultmapping/EntityResultTests.java @@ -152,8 +152,8 @@ public class EntityResultTests extends AbstractUsageTest { "select id as id_alias," + " type_code as type_code_alias," + " root_name as root_name_alias," - + " subtype1_name as subtype1_name_alias," - + " subtype2_name as subtype2_name_alias" + + " subtype1_name as sub_type1_name_alias," + + " subtype2_name as sub_type2_name_alias" + " from discriminated_entity"; final List results = session.createNativeQuery( qryString, "root-explicit" ).list();