diff --git a/hibernate-core/src/main/java/org/hibernate/generator/values/GeneratedValueBasicResultBuilder.java b/hibernate-core/src/main/java/org/hibernate/generator/values/GeneratedValueBasicResultBuilder.java index 776d7c20d9bd..7b9ae95ca0d4 100644 --- a/hibernate-core/src/main/java/org/hibernate/generator/values/GeneratedValueBasicResultBuilder.java +++ b/hibernate-core/src/main/java/org/hibernate/generator/values/GeneratedValueBasicResultBuilder.java @@ -16,6 +16,7 @@ import org.hibernate.sql.ast.tree.from.TableGroup; import org.hibernate.sql.ast.tree.from.TableReference; import org.hibernate.sql.results.graph.DomainResultCreationState; +import org.hibernate.sql.results.graph.Fetchable; import org.hibernate.sql.results.graph.basic.BasicResult; import org.hibernate.sql.results.jdbc.spi.JdbcValuesMetadata; @@ -60,7 +61,7 @@ public ResultBuilder cacheKeyInstance() { public BasicResult buildResult( JdbcValuesMetadata jdbcResultsMetadata, int resultPosition, - BiFunction legacyFetchResolver, + BiFunction legacyFetchResolver, DomainResultCreationState domainResultCreationState) { final DomainResultCreationStateImpl creationStateImpl = impl( domainResultCreationState ); diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/EntityIdentifierMapping.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/EntityIdentifierMapping.java index 045481c3abc8..bae24ed4e5af 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/EntityIdentifierMapping.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/EntityIdentifierMapping.java @@ -13,6 +13,7 @@ import jakarta.persistence.EmbeddedId; import jakarta.persistence.Id; import jakarta.persistence.IdClass; +import org.hibernate.sql.results.graph.Fetchable; /** @@ -22,7 +23,7 @@ * @see EmbeddedId * @see Nature */ -public interface EntityIdentifierMapping extends ValuedModelPart { +public interface EntityIdentifierMapping extends ValuedModelPart, Fetchable { String ID_ROLE_NAME = "{id}"; String LEGACY_ID_NAME = "id"; diff --git a/hibernate-core/src/main/java/org/hibernate/procedure/internal/EntityDomainResultBuilder.java b/hibernate-core/src/main/java/org/hibernate/procedure/internal/EntityDomainResultBuilder.java index ed464d188d82..3d768c11e06e 100644 --- a/hibernate-core/src/main/java/org/hibernate/procedure/internal/EntityDomainResultBuilder.java +++ b/hibernate-core/src/main/java/org/hibernate/procedure/internal/EntityDomainResultBuilder.java @@ -16,6 +16,7 @@ import org.hibernate.query.results.dynamic.DynamicFetchBuilderLegacy; import org.hibernate.query.results.implicit.ImplicitFetchBuilderBasic; import org.hibernate.sql.results.graph.DomainResultCreationState; +import org.hibernate.sql.results.graph.Fetchable; import org.hibernate.sql.results.graph.entity.EntityResult; import org.hibernate.sql.results.jdbc.spi.JdbcValuesMetadata; @@ -57,7 +58,7 @@ public ResultBuilder cacheKeyInstance() { public EntityResult buildResult( JdbcValuesMetadata jdbcResultsMetadata, int resultPosition, - BiFunction legacyFetchResolver, + BiFunction legacyFetchResolver, DomainResultCreationState domainResultCreationState) { return new EntityResultImpl( diff --git a/hibernate-core/src/main/java/org/hibernate/procedure/internal/ScalarDomainResultBuilder.java b/hibernate-core/src/main/java/org/hibernate/procedure/internal/ScalarDomainResultBuilder.java index e9fcadf19472..38fb16584de6 100644 --- a/hibernate-core/src/main/java/org/hibernate/procedure/internal/ScalarDomainResultBuilder.java +++ b/hibernate-core/src/main/java/org/hibernate/procedure/internal/ScalarDomainResultBuilder.java @@ -14,6 +14,7 @@ import org.hibernate.sql.ast.spi.SqlSelection; 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.basic.BasicResult; import org.hibernate.sql.results.jdbc.spi.JdbcValuesMetadata; import org.hibernate.type.BasicType; @@ -38,7 +39,7 @@ public Class getJavaType() { public DomainResult buildResult( JdbcValuesMetadata jdbcResultsMetadata, int resultPosition, - BiFunction legacyFetchResolver, + BiFunction legacyFetchResolver, DomainResultCreationState domainResultCreationState) { final SqlExpressionResolver sqlExpressionResolver = domainResultCreationState.getSqlAstCreationState() .getSqlExpressionResolver(); diff --git a/hibernate-core/src/main/java/org/hibernate/query/NativeQuery.java b/hibernate-core/src/main/java/org/hibernate/query/NativeQuery.java index 19b2939bf3c1..42bdacbbe8a9 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/NativeQuery.java +++ b/hibernate-core/src/main/java/org/hibernate/query/NativeQuery.java @@ -28,6 +28,7 @@ import org.hibernate.metamodel.mapping.PluralAttributeMapping; import org.hibernate.metamodel.model.domain.BasicDomainType; import org.hibernate.spi.NavigablePath; +import org.hibernate.sql.results.graph.Fetchable; import org.hibernate.transform.ResultTransformer; import org.hibernate.type.BasicTypeReference; @@ -505,6 +506,8 @@ interface FetchReturn extends ResultNode { String getOwnerAlias(); + Fetchable getFetchable(); + String getFetchableName(); /** diff --git a/hibernate-core/src/main/java/org/hibernate/query/internal/FetchMementoHbmStandard.java b/hibernate-core/src/main/java/org/hibernate/query/internal/FetchMementoHbmStandard.java index d3b9df8f1ca3..1d5e28eff5a8 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/internal/FetchMementoHbmStandard.java +++ b/hibernate-core/src/main/java/org/hibernate/query/internal/FetchMementoHbmStandard.java @@ -30,6 +30,7 @@ public class FetchMementoHbmStandard implements FetchMemento, FetchMemento.Parent { private static final String ELEMENT_PREFIX = "element."; + private static final int ELEMENT_PREFIX_LENGTH = 8; public interface FetchParentMemento { NavigablePath getNavigablePath(); @@ -74,55 +75,110 @@ public FetchBuilder resolve( Parent parent, Consumer querySpaceConsumer, ResultSetMappingResolutionContext context) { - final Map fetchBuilderMap = new HashMap<>(); - fetchMementoMap.forEach( - (attrName, fetchMemento) -> fetchBuilderMap.put( - attrName, - fetchMemento.resolve(this, querySpaceConsumer, context ) - ) - ); - final DynamicResultBuilderEntityStandard resultBuilder; - if ( fetchable instanceof PluralAttributeMapping ) { - resultBuilder = new DynamicResultBuilderEntityStandard( - (EntityMappingType) ( (PluralAttributeMapping) fetchable ).getElementDescriptor().getPartMappingType(), - tableAlias, - navigablePath - ); - FetchBuilder element = fetchBuilderMap.get( "element" ); - if ( element != null ) { - if ( element instanceof DynamicFetchBuilder ) { - resultBuilder.addIdColumnAliases( - ( (DynamicFetchBuilder) element ).getColumnAliases().toArray( new String[0] ) - ); - } - else { - resultBuilder.addIdColumnAliases( - ( (CompleteFetchBuilderEntityValuedModelPart) element ).getColumnAliases().toArray( new String[0] ) - ); - } - } - FetchBuilder index = fetchBuilderMap.get( "index" ); - if ( index != null ) { - resultBuilder.addFetchBuilder( CollectionPart.Nature.INDEX.getName(), index ); - } - for ( Map.Entry entry : fetchBuilderMap.entrySet() ) { - if ( entry.getKey().startsWith( ELEMENT_PREFIX ) ) { - resultBuilder.addFetchBuilder( entry.getKey().substring( ELEMENT_PREFIX.length() ), entry.getValue() ); - } - } + if ( fetchable instanceof PluralAttributeMapping pluralAttributeMapping ) { + return resolve( pluralAttributeMapping, querySpaceConsumer, context ); } else { - resultBuilder = new DynamicResultBuilderEntityStandard( - ( (ToOneAttributeMapping) fetchable ).getEntityMappingType(), - tableAlias, - navigablePath - ); - fetchBuilderMap.forEach( resultBuilder::addFetchBuilder ); + return resolve( (ToOneAttributeMapping) fetchable, querySpaceConsumer, context ); } + } + + private FetchBuilder resolve( + PluralAttributeMapping pluralAttributeMapping, + Consumer querySpaceConsumer, + ResultSetMappingResolutionContext context) { + final DynamicResultBuilderEntityStandard resultBuilder; + EntityMappingType partMappingType = (EntityMappingType) pluralAttributeMapping.getElementDescriptor() + .getPartMappingType(); + resultBuilder = new DynamicResultBuilderEntityStandard( + partMappingType, + tableAlias, + navigablePath + ); + final Map fetchBuilderMap = new HashMap<>(); + fetchMementoMap.forEach( + (attrName, fetchMemento) -> { + final FetchBuilder fetchBuilder = fetchMemento.resolve( this, querySpaceConsumer, context ); + + if ( attrName.equals( "element" ) ) { + if ( fetchBuilder instanceof DynamicFetchBuilder dynamicFetchBuilder ) { + resultBuilder.addIdColumnAliases( + dynamicFetchBuilder.getColumnAliases().toArray( new String[0] ) + ); + } + else { + resultBuilder.addIdColumnAliases( + ((CompleteFetchBuilderEntityValuedModelPart) fetchBuilder).getColumnAliases() + .toArray( new String[0] ) + ); + } + fetchBuilderMap.put( + pluralAttributeMapping.getElementDescriptor(), + fetchBuilder + ); + } + else if ( attrName.equals( "index" ) ) { + final CollectionPart indexDescriptor = pluralAttributeMapping.getIndexDescriptor(); + resultBuilder.addFetchBuilder( indexDescriptor, fetchBuilder ); + fetchBuilderMap.put( + indexDescriptor, + fetchBuilder + ); + } + else if ( attrName.startsWith( ELEMENT_PREFIX ) ) { + final Fetchable attributeMapping = (Fetchable) partMappingType.findByPath( + attrName.substring( ELEMENT_PREFIX_LENGTH ) ); + resultBuilder.addFetchBuilder( attributeMapping, fetchBuilder ); + fetchBuilderMap.put( + attributeMapping, + fetchBuilder + ); + } + else { + final Fetchable attributeMapping = (Fetchable) partMappingType.findByPath( attrName ); + resultBuilder.addFetchBuilder( attributeMapping, fetchBuilder ); + fetchBuilderMap.put( + attributeMapping, + fetchBuilder + ); + } + } + ); + return new DynamicFetchBuilderLegacy( + tableAlias, + ownerTableAlias, + fetchable, + keyColumnNames, + fetchBuilderMap, + resultBuilder + ); + } + + private FetchBuilder resolve( + ToOneAttributeMapping toOneAttributeMapping, + Consumer querySpaceConsumer, + ResultSetMappingResolutionContext context) { + final Map fetchBuilderMap = new HashMap<>(); + fetchMementoMap.forEach( + (attrName, fetchMemento) -> + fetchBuilderMap.put( + (Fetchable) toOneAttributeMapping.findSubPart( attrName ), + fetchMemento.resolve( this, querySpaceConsumer, context ) + ) + ); + final DynamicResultBuilderEntityStandard resultBuilder; + resultBuilder = new DynamicResultBuilderEntityStandard( + toOneAttributeMapping.getEntityMappingType(), + tableAlias, + navigablePath + ); + fetchBuilderMap.forEach( (fetchable, fetchBuilder) -> + resultBuilder.addFetchBuilder( fetchable, fetchBuilder ) + ); return new DynamicFetchBuilderLegacy( tableAlias, ownerTableAlias, - fetchable.getFetchableName(), + fetchable, keyColumnNames, fetchBuilderMap, resultBuilder diff --git a/hibernate-core/src/main/java/org/hibernate/query/internal/ResultMementoEntityJpa.java b/hibernate-core/src/main/java/org/hibernate/query/internal/ResultMementoEntityJpa.java index 2acddfd1ae3b..f99ceacde226 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/internal/ResultMementoEntityJpa.java +++ b/hibernate-core/src/main/java/org/hibernate/query/internal/ResultMementoEntityJpa.java @@ -23,6 +23,7 @@ import org.hibernate.query.results.complete.DelayedFetchBuilderBasicPart; import org.hibernate.query.results.implicit.ImplicitFetchBuilderBasic; import org.hibernate.spi.NavigablePath; +import org.hibernate.sql.results.graph.Fetchable; /** * @author Steve Ebersole @@ -70,13 +71,13 @@ public ResultBuilderEntityValued resolve( } } - final HashMap explicitFetchBuilderMap = new HashMap<>(); + final HashMap explicitFetchBuilderMap = new HashMap<>(); // If there are no explicit fetches, we don't register DELAYED builders to get implicit fetching of all basic fetchables if ( !explicitFetchMementoMap.isEmpty() ) { explicitFetchMementoMap.forEach( (relativePath, fetchMemento) -> explicitFetchBuilderMap.put( - relativePath, + (Fetchable) entityDescriptor.findByPath( relativePath ), fetchMemento.resolve( this, querySpaceConsumer, context ) ) ); @@ -87,13 +88,13 @@ public ResultBuilderEntityValued resolve( attributeMapping -> { final BasicValuedModelPart basicPart = attributeMapping.asBasicValuedModelPart(); if ( basicPart != null ) { - final Function fetchBuilderCreator = k -> new DelayedFetchBuilderBasicPart( - navigablePath.append( k ), + final Function fetchBuilderCreator = k -> new DelayedFetchBuilderBasicPart( + navigablePath.append( k.getFetchableName() ), basicPart, isEnhancedForLazyLoading ); explicitFetchBuilderMap.computeIfAbsent( - attributeMapping.getFetchableName(), + attributeMapping, fetchBuilderCreator ); } diff --git a/hibernate-core/src/main/java/org/hibernate/query/internal/ResultMementoEntityStandard.java b/hibernate-core/src/main/java/org/hibernate/query/internal/ResultMementoEntityStandard.java index 249d3c718c77..af0aa19c9043 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/internal/ResultMementoEntityStandard.java +++ b/hibernate-core/src/main/java/org/hibernate/query/internal/ResultMementoEntityStandard.java @@ -19,6 +19,7 @@ import org.hibernate.query.results.FetchBuilder; import org.hibernate.query.results.ResultBuilderEntityValued; import org.hibernate.query.results.complete.CompleteResultBuilderEntityStandard; +import org.hibernate.sql.results.graph.Fetchable; /** * @author Steve Ebersole @@ -64,11 +65,11 @@ public ResultBuilderEntityValued resolve( ? (BasicValuedFetchBuilder) discriminatorMemento.resolve( this, querySpaceConsumer, context ) : null; - final HashMap fetchBuilderMap = new HashMap<>(); + final HashMap fetchBuilderMap = new HashMap<>(); fetchMementoMap.forEach( (attrName, fetchMemento) -> fetchBuilderMap.put( - attrName, + (Fetchable) entityDescriptor.findByPath( attrName ), fetchMemento.resolve(this, querySpaceConsumer, context ) ) ); diff --git a/hibernate-core/src/main/java/org/hibernate/query/results/BasicValuedFetchBuilder.java b/hibernate-core/src/main/java/org/hibernate/query/results/BasicValuedFetchBuilder.java index 2cb5548bcd5d..45bde5b7e658 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/results/BasicValuedFetchBuilder.java +++ b/hibernate-core/src/main/java/org/hibernate/query/results/BasicValuedFetchBuilder.java @@ -10,6 +10,7 @@ import org.hibernate.query.results.dynamic.DynamicFetchBuilderLegacy; import org.hibernate.sql.results.graph.DomainResultCreationState; import org.hibernate.sql.results.graph.FetchParent; +import org.hibernate.sql.results.graph.Fetchable; import org.hibernate.sql.results.graph.basic.BasicFetch; import org.hibernate.sql.results.jdbc.spi.JdbcValuesMetadata; @@ -22,6 +23,6 @@ BasicFetch buildFetch( FetchParent parent, NavigablePath fetchPath, JdbcValuesMetadata jdbcResultsMetadata, - BiFunction legacyFetchResolver, + BiFunction legacyFetchResolver, DomainResultCreationState domainResultCreationState); } 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 b541a8ec099e..0e1abe4d8747 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 @@ -235,8 +235,8 @@ public static DynamicResultBuilderEntityCalculated entityCalculated( return new DynamicResultBuilderEntityCalculated( entityMapping, tableAlias, explicitLockMode ); } - public static DynamicFetchBuilderLegacy fetch(String tableAlias, String ownerTableAlias, String joinPropertyName) { - return new DynamicFetchBuilderLegacy( tableAlias, ownerTableAlias, joinPropertyName, new ArrayList<>(), new HashMap<>() ); + public static DynamicFetchBuilderLegacy fetch(String tableAlias, String ownerTableAlias, Fetchable fetchable) { + return new DynamicFetchBuilderLegacy( tableAlias, ownerTableAlias, fetchable, new ArrayList<>(), new HashMap<>() ); } public static ResultBuilder resultClassBuilder( @@ -269,7 +269,7 @@ public static ImplicitFetchBuilder implicitFetchBuilder( DomainResultCreationState creationState) { final BasicValuedModelPart basicValuedFetchable = fetchable.asBasicValuedModelPart(); if ( basicValuedFetchable != null ) { - return new ImplicitFetchBuilderBasic( fetchPath, basicValuedFetchable, creationState ); + return new ImplicitFetchBuilderBasic( fetchPath, fetchable, basicValuedFetchable, creationState ); } if ( fetchable instanceof EmbeddableValuedFetchable ) { 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 956be35b2a13..9de6b9af4699 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 @@ -4,7 +4,6 @@ */ package org.hibernate.query.results; -import java.util.AbstractMap; import java.util.HashMap; import java.util.Map; import java.util.function.Consumer; @@ -19,16 +18,11 @@ import org.hibernate.internal.util.collections.StandardStack; import org.hibernate.metamodel.mapping.Association; import org.hibernate.metamodel.mapping.AssociationKey; -import org.hibernate.metamodel.mapping.AttributeMapping; -import org.hibernate.metamodel.mapping.CompositeIdentifierMapping; import org.hibernate.metamodel.mapping.EntityIdentifierMapping; import org.hibernate.metamodel.mapping.EntityValuedModelPart; import org.hibernate.metamodel.mapping.ForeignKeyDescriptor; import org.hibernate.metamodel.mapping.ModelPart; -import org.hibernate.metamodel.mapping.NonAggregatedIdentifierMapping; -import org.hibernate.metamodel.mapping.internal.BasicValuedCollectionPart; import org.hibernate.metamodel.mapping.internal.CaseStatementDiscriminatorMappingImpl; -import org.hibernate.metamodel.mapping.internal.SingleAttributeIdentifierMapping; import org.hibernate.spi.EntityIdentifierNavigablePath; import org.hibernate.spi.NavigablePath; import org.hibernate.query.results.dynamic.DynamicFetchBuilderLegacy; @@ -80,7 +74,6 @@ public class DomainResultCreationStateImpl private final SessionFactoryImplementor sessionFactory; private final Stack fetchBuilderResolverStack = new StandardStack<>( Function.class, fetchableName -> null ); - private final Stack relativePathStack = new StandardStack<>( Map.Entry.class ); private Map registeredLockModes; private boolean processingKeyFetches = false; private boolean resolvingCircularFetch; @@ -89,7 +82,7 @@ public class DomainResultCreationStateImpl public DomainResultCreationStateImpl( String stateIdentifier, JdbcValuesMetadata jdbcResultsMetadata, - Map> legacyFetchBuilders, + Map> legacyFetchBuilders, Consumer sqlSelectionConsumer, LoadQueryInfluencers loadQueryInfluencers, SessionFactoryImplementor sessionFactory) { @@ -130,30 +123,26 @@ public JdbcValuesMetadata getJdbcResultsMetadata() { return jdbcResultsMetadata; } - public Map.Entry getCurrentRelativePath() { - return relativePathStack.getCurrent(); - } - - public void pushExplicitFetchMementoResolver(Function resolver) { + public void pushExplicitFetchMementoResolver(Function resolver) { fetchBuilderResolverStack.push( resolver ); } - public Function getCurrentExplicitFetchMementoResolver() { + public Function getCurrentExplicitFetchMementoResolver() { return fetchBuilderResolverStack.getCurrent(); } - public Function popExplicitFetchMementoResolver() { + public Function popExplicitFetchMementoResolver() { return fetchBuilderResolverStack.pop(); } @SuppressWarnings( "unused" ) - public void withExplicitFetchMementoResolver(Function resolver, Runnable runnable) { + public void withExplicitFetchMementoResolver(Function resolver, Runnable runnable) { pushExplicitFetchMementoResolver( resolver ); try { runnable.run(); } finally { - final Function popped = popExplicitFetchMementoResolver(); + final Function popped = popExplicitFetchMementoResolver(); assert popped == resolver; } } @@ -283,8 +272,7 @@ public Expression resolveSqlExpression( sqlSelectionMap.put( key, (ResultSetMappingSqlSelection) created ); sqlSelectionConsumer.accept( (ResultSetMappingSqlSelection) created ); } - else if ( created instanceof ColumnReference ) { - final ColumnReference columnReference = (ColumnReference) created; + else if ( created instanceof ColumnReference columnReference) { final String selectableName = columnReference.getSelectableName(); final int valuesArrayPosition; if ( nestingFetchParent != null ) { @@ -342,19 +330,19 @@ public SqlSelection resolveSqlSelection( } private static class LegacyFetchResolverImpl implements LegacyFetchResolver { - private final Map> legacyFetchBuilders; + private final Map> legacyFetchBuilders; - public LegacyFetchResolverImpl(Map> legacyFetchBuilders) { + public LegacyFetchResolverImpl(Map> legacyFetchBuilders) { this.legacyFetchBuilders = legacyFetchBuilders; } @Override - public DynamicFetchBuilderLegacy resolve(String ownerTableAlias, String fetchedPartPath) { + public DynamicFetchBuilderLegacy resolve(String ownerTableAlias, Fetchable fetchedPartPath) { if ( legacyFetchBuilders == null ) { return null; } - final Map fetchBuilders = legacyFetchBuilders.get( ownerTableAlias ); + final Map fetchBuilders = legacyFetchBuilders.get( ownerTableAlias ); if ( fetchBuilders == null ) { return null; } @@ -377,28 +365,17 @@ public Fetch visitIdentifierFetch(EntityResultGraphNode fetchParent) { final EntityValuedModelPart parentModelPart = fetchParent.getEntityValuedModelPart(); final EntityIdentifierMapping identifierMapping = parentModelPart.getEntityMappingType().getIdentifierMapping(); final String identifierAttributeName = attributeName( identifierMapping ); - final Map.Entry oldEntry = relativePathStack.getCurrent(); - final String fullPath; - if ( identifierMapping instanceof NonAggregatedIdentifierMapping ) { - fullPath = oldEntry == null ? "" : oldEntry.getKey(); - } - else { - fullPath = oldEntry == null ? - identifierAttributeName : - oldEntry.getKey() + "." + identifierAttributeName; - } - final Fetchable identifierFetchable = (Fetchable) identifierMapping; final FetchBuilder explicitFetchBuilder = (FetchBuilder) fetchBuilderResolverStack .getCurrent() - .apply( fullPath ); + .apply( identifierMapping ); DynamicFetchBuilderLegacy fetchBuilderLegacy; if ( explicitFetchBuilder == null ) { fetchBuilderLegacy = legacyFetchResolver.resolve( fromClauseAccess.findTableGroup( fetchParent.getNavigablePath() ) .getPrimaryTableReference() .getIdentificationVariable(), - identifierAttributeName + identifierMapping ); } else { @@ -412,9 +389,6 @@ public Fetch visitIdentifierFetch(EntityResultGraphNode fetchParent) { final boolean processingKeyFetches = this.processingKeyFetches; this.processingKeyFetches = true; - if ( identifierMapping instanceof CompositeIdentifierMapping ) { - relativePathStack.push( new AbstractMap.SimpleEntry<>( fullPath, fetchPath ) ); - } try { final FetchBuilder fetchBuilder; @@ -423,7 +397,7 @@ public Fetch visitIdentifierFetch(EntityResultGraphNode fetchParent) { } else { if ( fetchBuilderLegacy == null ) { - fetchBuilder = Builders.implicitFetchBuilder( fetchPath, identifierFetchable, this ); + fetchBuilder = Builders.implicitFetchBuilder( fetchPath, identifierMapping, this ); } else { fetchBuilder = fetchBuilderLegacy; @@ -441,9 +415,6 @@ public Fetch visitIdentifierFetch(EntityResultGraphNode fetchParent) { } finally { this.processingKeyFetches = processingKeyFetches; - if ( identifierMapping instanceof CompositeIdentifierMapping ) { - this.relativePathStack.pop(); - } } } @@ -462,110 +433,64 @@ private Consumer createFetchableConsumer(FetchParent fetchParent, Imm if ( !fetchable.isSelectable() ) { return; } - final String fetchableName = fetchable.getFetchableName(); - Map.Entry currentEntry; - if ( relativePathStack.isEmpty() ) { - currentEntry = new AbstractMap.SimpleEntry<>( - getRelativePath( "", fetchable ), - new NavigablePath( fetchableName ) - ); - } - else { - final Map.Entry oldEntry = relativePathStack.getCurrent(); - final String key = oldEntry.getKey(); - currentEntry = new AbstractMap.SimpleEntry<>( - getRelativePath( key, fetchable ), - oldEntry.getValue().append( fetchableName ) - ); - } - // todo (6.0): figure out if we can somehow create the navigable paths in a better way - final String fullPath = currentEntry.getKey(); FetchBuilder explicitFetchBuilder = (FetchBuilder) fetchBuilderResolverStack .getCurrent() - .apply( fullPath ); + .apply( fetchable ); DynamicFetchBuilderLegacy fetchBuilderLegacy; if ( explicitFetchBuilder == null ) { fetchBuilderLegacy = legacyFetchResolver.resolve( fromClauseAccess.findTableGroup( fetchParent.getNavigablePath() ) .getPrimaryTableReference() .getIdentificationVariable(), - fetchableName + fetchable ); } else { fetchBuilderLegacy = null; } - if ( fetchable instanceof Association && fetchable.getMappedFetchOptions().getTiming() == FetchTiming.DELAYED ) { - final Association association = (Association) fetchable; + if ( fetchable instanceof Association association && fetchable.getMappedFetchOptions().getTiming() == FetchTiming.DELAYED ) { final ForeignKeyDescriptor foreignKeyDescriptor = association.getForeignKeyDescriptor(); - - final String partName = attributeName( - foreignKeyDescriptor.getSide( association.getSideNature().inverse() ).getModelPart() - ); - // If there are no fetch builders for this association, we only want to fetch the FK - if ( explicitFetchBuilder == null && fetchBuilderLegacy == null && partName != null ) { - currentEntry = new AbstractMap.SimpleEntry<>( - currentEntry.getKey() + "." + partName, - currentEntry.getValue().append( partName ) - ); + if ( explicitFetchBuilder == null && fetchBuilderLegacy == null ) { explicitFetchBuilder = (FetchBuilder) fetchBuilderResolverStack .getCurrent() - .apply( currentEntry.getKey() ); + .apply( foreignKeyDescriptor.getSide( association.getSideNature().inverse() ).getModelPart() ); if ( explicitFetchBuilder == null ) { fetchBuilderLegacy = legacyFetchResolver.resolve( fromClauseAccess.findTableGroup( fetchParent.getNavigablePath() ) .getPrimaryTableReference() .getIdentificationVariable(), - fetchableName + fetchable ); } } } - relativePathStack.push( currentEntry ); - try { - - final NavigablePath fetchPath = fetchParent.resolveNavigablePath( fetchable ); - final FetchBuilder fetchBuilder; - if ( explicitFetchBuilder != null ) { - fetchBuilder = explicitFetchBuilder; + final NavigablePath fetchPath = fetchParent.resolveNavigablePath( fetchable ); + final FetchBuilder fetchBuilder; + if ( explicitFetchBuilder != null ) { + fetchBuilder = explicitFetchBuilder; + } + else { + if ( fetchBuilderLegacy == null ) { + fetchBuilder = Builders.implicitFetchBuilder( fetchPath, fetchable, this ); } else { - if ( fetchBuilderLegacy == null ) { - fetchBuilder = Builders.implicitFetchBuilder( fetchPath, fetchable, this ); - } - else { - fetchBuilder = fetchBuilderLegacy; - } + fetchBuilder = fetchBuilderLegacy; } - final Fetch fetch = fetchBuilder.buildFetch( - fetchParent, - fetchPath, - jdbcResultsMetadata, - (s, s2) -> { - throw new UnsupportedOperationException(); - }, - this - ); - fetches.add( fetch ); - } - finally { - relativePathStack.pop(); } - + final Fetch fetch = fetchBuilder.buildFetch( + fetchParent, + fetchPath, + jdbcResultsMetadata, + (s, s2) -> { + throw new UnsupportedOperationException(); + }, + this + ); + fetches.add( fetch ); }; } - private String getRelativePath(String oldEntry, Fetchable fetchable) { - if ( fetchable instanceof AttributeMapping || fetchable instanceof SingleAttributeIdentifierMapping || fetchable instanceof BasicValuedCollectionPart ) { - if ( !oldEntry.equals( "" ) ) { - return oldEntry + '.' + fetchable.getFetchableName(); - } - return fetchable.getFetchableName(); - } - return oldEntry; - } - @Override public boolean isResolvingCircularFetch() { return resolvingCircularFetch; diff --git a/hibernate-core/src/main/java/org/hibernate/query/results/FetchBuilder.java b/hibernate-core/src/main/java/org/hibernate/query/results/FetchBuilder.java index d65dcd580e58..b3c003182b21 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/results/FetchBuilder.java +++ b/hibernate-core/src/main/java/org/hibernate/query/results/FetchBuilder.java @@ -14,6 +14,7 @@ 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.jdbc.spi.JdbcValuesMetadata; /** @@ -29,10 +30,10 @@ Fetch buildFetch( FetchParent parent, NavigablePath fetchPath, JdbcValuesMetadata jdbcResultsMetadata, - BiFunction legacyFetchResolver, + BiFunction legacyFetchResolver, DomainResultCreationState domainResultCreationState); - default void visitFetchBuilders(BiConsumer consumer) { + default void visitFetchBuilders(BiConsumer consumer) { } FetchBuilder cacheKeyInstance(); diff --git a/hibernate-core/src/main/java/org/hibernate/query/results/ImplicitAttributeFetchBuilder.java b/hibernate-core/src/main/java/org/hibernate/query/results/ImplicitAttributeFetchBuilder.java index 85b141112230..d2465a127ef5 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/results/ImplicitAttributeFetchBuilder.java +++ b/hibernate-core/src/main/java/org/hibernate/query/results/ImplicitAttributeFetchBuilder.java @@ -14,6 +14,7 @@ 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.jdbc.spi.JdbcValuesMetadata; /** @@ -40,7 +41,7 @@ public Fetch buildFetch( FetchParent parent, NavigablePath fetchPath, JdbcValuesMetadata jdbcResultsMetadata, - BiFunction legacyFetchResolver, + BiFunction legacyFetchResolver, DomainResultCreationState domainResultCreationState) { assert fetchPath.equals( navigablePath ); diff --git a/hibernate-core/src/main/java/org/hibernate/query/results/ResultBuilder.java b/hibernate-core/src/main/java/org/hibernate/query/results/ResultBuilder.java index 8893ec89c631..ded5111a78ec 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/results/ResultBuilder.java +++ b/hibernate-core/src/main/java/org/hibernate/query/results/ResultBuilder.java @@ -11,6 +11,7 @@ import org.hibernate.query.results.dynamic.DynamicFetchBuilderLegacy; 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.jdbc.spi.JdbcValuesMetadata; /** @@ -24,13 +25,13 @@ public interface ResultBuilder { DomainResult buildResult( JdbcValuesMetadata jdbcResultsMetadata, int resultPosition, - BiFunction legacyFetchResolver, + BiFunction legacyFetchResolver, DomainResultCreationState domainResultCreationState); Class getJavaType(); ResultBuilder cacheKeyInstance(); - default void visitFetchBuilders(BiConsumer consumer) { + default void visitFetchBuilders(BiConsumer consumer) { } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/results/ResultBuilderBasicValued.java b/hibernate-core/src/main/java/org/hibernate/query/results/ResultBuilderBasicValued.java index 7055dc7b1d74..934583a8728e 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/results/ResultBuilderBasicValued.java +++ b/hibernate-core/src/main/java/org/hibernate/query/results/ResultBuilderBasicValued.java @@ -8,6 +8,7 @@ import org.hibernate.query.results.dynamic.DynamicFetchBuilderLegacy; import org.hibernate.sql.results.graph.DomainResultCreationState; +import org.hibernate.sql.results.graph.Fetchable; import org.hibernate.sql.results.graph.basic.BasicResult; import org.hibernate.sql.results.jdbc.spi.JdbcValuesMetadata; @@ -21,6 +22,6 @@ public interface ResultBuilderBasicValued extends ResultBuilder { BasicResult buildResult( JdbcValuesMetadata jdbcResultsMetadata, int resultPosition, - BiFunction legacyFetchResolver, + BiFunction legacyFetchResolver, DomainResultCreationState domainResultCreationState); } diff --git a/hibernate-core/src/main/java/org/hibernate/query/results/ResultBuilderEmbeddable.java b/hibernate-core/src/main/java/org/hibernate/query/results/ResultBuilderEmbeddable.java index 7debb74ce08f..99f48974a051 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/results/ResultBuilderEmbeddable.java +++ b/hibernate-core/src/main/java/org/hibernate/query/results/ResultBuilderEmbeddable.java @@ -8,6 +8,7 @@ import org.hibernate.query.results.dynamic.DynamicFetchBuilderLegacy; import org.hibernate.sql.results.graph.DomainResultCreationState; +import org.hibernate.sql.results.graph.Fetchable; import org.hibernate.sql.results.graph.embeddable.EmbeddableResult; import org.hibernate.sql.results.jdbc.spi.JdbcValuesMetadata; @@ -19,6 +20,6 @@ public interface ResultBuilderEmbeddable extends ResultBuilder { EmbeddableResult buildResult( JdbcValuesMetadata jdbcResultsMetadata, int resultPosition, - BiFunction legacyFetchResolver, + BiFunction legacyFetchResolver, DomainResultCreationState domainResultCreationState); } diff --git a/hibernate-core/src/main/java/org/hibernate/query/results/ResultBuilderEntityValued.java b/hibernate-core/src/main/java/org/hibernate/query/results/ResultBuilderEntityValued.java index 7c9d041c151d..e8ce532b1289 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/results/ResultBuilderEntityValued.java +++ b/hibernate-core/src/main/java/org/hibernate/query/results/ResultBuilderEntityValued.java @@ -8,6 +8,7 @@ import org.hibernate.query.results.dynamic.DynamicFetchBuilderLegacy; import org.hibernate.sql.results.graph.DomainResultCreationState; +import org.hibernate.sql.results.graph.Fetchable; import org.hibernate.sql.results.graph.entity.EntityResult; import org.hibernate.sql.results.jdbc.spi.JdbcValuesMetadata; @@ -21,6 +22,6 @@ public interface ResultBuilderEntityValued extends ResultBuilder { EntityResult buildResult( JdbcValuesMetadata jdbcResultsMetadata, int resultPosition, - BiFunction legacyFetchResolver, + BiFunction legacyFetchResolver, DomainResultCreationState domainResultCreationState); } diff --git a/hibernate-core/src/main/java/org/hibernate/query/results/ResultSetMappingImpl.java b/hibernate-core/src/main/java/org/hibernate/query/results/ResultSetMappingImpl.java index 8742d54ca3f1..9ea5247a0982 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/results/ResultSetMappingImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/query/results/ResultSetMappingImpl.java @@ -27,6 +27,7 @@ import org.hibernate.query.results.dynamic.DynamicFetchBuilderLegacy; import org.hibernate.sql.ast.spi.SqlSelection; import org.hibernate.sql.results.graph.DomainResult; +import org.hibernate.sql.results.graph.Fetchable; import org.hibernate.sql.results.graph.basic.BasicResult; import org.hibernate.sql.results.graph.entity.EntityResult; import org.hibernate.sql.results.jdbc.spi.JdbcValuesMapping; @@ -43,7 +44,7 @@ public class ResultSetMappingImpl implements ResultSetMapping { private final String mappingIdentifier; private final boolean isDynamic; private List resultBuilders; - private Map> legacyFetchBuilders; + private Map> legacyFetchBuilders; public ResultSetMappingImpl(String mappingIdentifier) { this( mappingIdentifier, false ); @@ -71,15 +72,15 @@ private ResultSetMappingImpl(ResultSetMappingImpl original) { this.legacyFetchBuilders = null; } else { - final Map> legacyFetchBuilders = new HashMap<>( original.legacyFetchBuilders.size() ); - for ( Map.Entry> entry : original.legacyFetchBuilders.entrySet() ) { - final Map newValue = new HashMap<>( entry.getValue().size() ); - for ( Map.Entry builderEntry : entry.getValue().entrySet() ) { + final Map> builders = new HashMap<>( original.legacyFetchBuilders.size() ); + for ( Map.Entry> entry : original.legacyFetchBuilders.entrySet() ) { + final Map newValue = new HashMap<>( entry.getValue().size() ); + for ( Map.Entry builderEntry : entry.getValue().entrySet() ) { newValue.put( builderEntry.getKey(), builderEntry.getValue().cacheKeyInstance() ); } - legacyFetchBuilders.put( entry.getKey(), newValue ); + builders.put( entry.getKey(), newValue ); } - this.legacyFetchBuilders = legacyFetchBuilders; + this.legacyFetchBuilders = builders; } } @@ -122,7 +123,7 @@ public void visitLegacyFetchBuilders(Consumer resultB return; } - for ( Map.Entry> entry : legacyFetchBuilders.entrySet() ) { + for ( Map.Entry> entry : legacyFetchBuilders.entrySet() ) { for ( DynamicFetchBuilderLegacy fetchBuilder : entry.getValue().values() ) { resultBuilderConsumer.accept( fetchBuilder ); } @@ -139,7 +140,7 @@ public void addResultBuilder(ResultBuilder resultBuilder) { @Override public void addLegacyFetchBuilder(DynamicFetchBuilderLegacy fetchBuilder) { - final Map existingFetchBuildersByOwner; + final Map existingFetchBuildersByOwner; if ( legacyFetchBuilders == null ) { legacyFetchBuilders = new HashMap<>(); @@ -149,7 +150,7 @@ public void addLegacyFetchBuilder(DynamicFetchBuilderLegacy fetchBuilder) { existingFetchBuildersByOwner = legacyFetchBuilders.get( fetchBuilder.getOwnerAlias() ); } - final Map fetchBuildersByOwner; + final Map fetchBuildersByOwner; if ( existingFetchBuildersByOwner == null ) { fetchBuildersByOwner = new HashMap<>(); legacyFetchBuilders.put( fetchBuilder.getOwnerAlias(), fetchBuildersByOwner ); @@ -158,7 +159,7 @@ public void addLegacyFetchBuilder(DynamicFetchBuilderLegacy fetchBuilder) { fetchBuildersByOwner = existingFetchBuildersByOwner; } - final DynamicFetchBuilderLegacy previousBuilder = fetchBuildersByOwner.put( fetchBuilder.getFetchableName(), fetchBuilder ); + final DynamicFetchBuilderLegacy previousBuilder = fetchBuildersByOwner.put( fetchBuilder.getFetchable(), fetchBuilder ); if ( previousBuilder != null ) { // todo (6.0) : error? log? nothing? } diff --git a/hibernate-core/src/main/java/org/hibernate/query/results/ResultsHelper.java b/hibernate-core/src/main/java/org/hibernate/query/results/ResultsHelper.java index cf7aabf9580b..cdf5942271e4 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/results/ResultsHelper.java +++ b/hibernate-core/src/main/java/org/hibernate/query/results/ResultsHelper.java @@ -4,6 +4,7 @@ */ package org.hibernate.query.results; +import org.hibernate.metamodel.mapping.EntityDiscriminatorMapping; import org.hibernate.metamodel.mapping.EntityIdentifierMapping; import org.hibernate.metamodel.mapping.ModelPart; import org.hibernate.metamodel.mapping.SelectableMapping; @@ -19,6 +20,7 @@ import org.hibernate.sql.results.jdbc.spi.JdbcValuesMetadata; import static org.hibernate.sql.ast.spi.SqlExpressionResolver.createColumnReferenceKey; +import static org.hibernate.sql.ast.spi.SqlExpressionResolver.createDiscriminatorColumnReferenceKey; /** * @author Steve Ebersole @@ -65,6 +67,25 @@ public static Expression resolveSqlExpression( ); } + public static Expression resolveSqlExpression( + DomainResultCreationStateImpl resolver, + JdbcValuesMetadata jdbcValuesMetadata, + TableReference tableReference, + EntityDiscriminatorMapping discriminatorMapping, + String columnAlias) { + return resolver.resolveSqlExpression( + createDiscriminatorColumnReferenceKey( + tableReference, + discriminatorMapping + ), + processingState -> { + final int jdbcPosition = jdbcValuesMetadata.resolveColumnPosition( columnAlias ); + final int valuesArrayPosition = jdbcPositionToValuesArrayPosition( jdbcPosition ); + return new ResultSetMappingSqlSelection( valuesArrayPosition, discriminatorMapping.getJdbcMapping() ); + } + ); + } + public static Expression resolveSqlExpression( DomainResultCreationStateImpl resolver, TableReference tableReference, diff --git a/hibernate-core/src/main/java/org/hibernate/query/results/complete/CompleteFetchBuilderBasicPart.java b/hibernate-core/src/main/java/org/hibernate/query/results/complete/CompleteFetchBuilderBasicPart.java index e79924b8febc..20b56fa473ea 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/results/complete/CompleteFetchBuilderBasicPart.java +++ b/hibernate-core/src/main/java/org/hibernate/query/results/complete/CompleteFetchBuilderBasicPart.java @@ -25,6 +25,7 @@ import org.hibernate.sql.ast.tree.from.TableReference; import org.hibernate.sql.results.graph.DomainResultCreationState; import org.hibernate.sql.results.graph.FetchParent; +import org.hibernate.sql.results.graph.Fetchable; import org.hibernate.sql.results.graph.basic.BasicFetch; import org.hibernate.sql.results.jdbc.spi.JdbcValuesMetadata; @@ -74,7 +75,7 @@ public BasicFetch buildFetch( FetchParent parent, NavigablePath fetchPath, JdbcValuesMetadata jdbcResultsMetadata, - BiFunction legacyFetchResolver, + BiFunction legacyFetchResolver, DomainResultCreationState domainResultCreationState) { final DomainResultCreationStateImpl creationStateImpl = impl( domainResultCreationState ); diff --git a/hibernate-core/src/main/java/org/hibernate/query/results/complete/CompleteFetchBuilderEmbeddableValuedModelPart.java b/hibernate-core/src/main/java/org/hibernate/query/results/complete/CompleteFetchBuilderEmbeddableValuedModelPart.java index 1441f9538e98..ad56ffec7e8b 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/results/complete/CompleteFetchBuilderEmbeddableValuedModelPart.java +++ b/hibernate-core/src/main/java/org/hibernate/query/results/complete/CompleteFetchBuilderEmbeddableValuedModelPart.java @@ -19,6 +19,7 @@ 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.jdbc.spi.JdbcValuesMetadata; import static org.hibernate.query.results.ResultsHelper.impl; @@ -72,7 +73,7 @@ public Fetch buildFetch( FetchParent parent, NavigablePath fetchPath, JdbcValuesMetadata jdbcResultsMetadata, - BiFunction legacyFetchResolver, + BiFunction legacyFetchResolver, DomainResultCreationState domainResultCreationState) { assert fetchPath.equals( navigablePath ); final DomainResultCreationStateImpl creationStateImpl = impl( domainResultCreationState ); diff --git a/hibernate-core/src/main/java/org/hibernate/query/results/complete/CompleteFetchBuilderEntityValuedModelPart.java b/hibernate-core/src/main/java/org/hibernate/query/results/complete/CompleteFetchBuilderEntityValuedModelPart.java index 65c8e5f71599..c36158d56d04 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/results/complete/CompleteFetchBuilderEntityValuedModelPart.java +++ b/hibernate-core/src/main/java/org/hibernate/query/results/complete/CompleteFetchBuilderEntityValuedModelPart.java @@ -19,6 +19,7 @@ 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.entity.EntityValuedFetchable; import org.hibernate.sql.results.jdbc.spi.JdbcValuesMetadata; @@ -73,7 +74,7 @@ public Fetch buildFetch( FetchParent parent, NavigablePath fetchPath, JdbcValuesMetadata jdbcResultsMetadata, - BiFunction legacyFetchResolver, + BiFunction legacyFetchResolver, DomainResultCreationState domainResultCreationState) { assert fetchPath.equals( navigablePath ); final DomainResultCreationStateImpl creationStateImpl = impl( domainResultCreationState ); diff --git a/hibernate-core/src/main/java/org/hibernate/query/results/complete/CompleteResultBuilderBasicModelPart.java b/hibernate-core/src/main/java/org/hibernate/query/results/complete/CompleteResultBuilderBasicModelPart.java index 322662a80d24..62091e94b094 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/results/complete/CompleteResultBuilderBasicModelPart.java +++ b/hibernate-core/src/main/java/org/hibernate/query/results/complete/CompleteResultBuilderBasicModelPart.java @@ -16,6 +16,7 @@ import org.hibernate.sql.ast.tree.from.TableGroup; import org.hibernate.sql.ast.tree.from.TableReference; import org.hibernate.sql.results.graph.DomainResultCreationState; +import org.hibernate.sql.results.graph.Fetchable; import org.hibernate.sql.results.graph.basic.BasicResult; import org.hibernate.sql.results.jdbc.spi.JdbcValuesMetadata; @@ -65,7 +66,7 @@ public ResultBuilder cacheKeyInstance() { public BasicResult buildResult( JdbcValuesMetadata jdbcResultsMetadata, int resultPosition, - BiFunction legacyFetchResolver, + BiFunction legacyFetchResolver, DomainResultCreationState domainResultCreationState) { final DomainResultCreationStateImpl creationStateImpl = impl( domainResultCreationState ); diff --git a/hibernate-core/src/main/java/org/hibernate/query/results/complete/CompleteResultBuilderBasicValuedConverted.java b/hibernate-core/src/main/java/org/hibernate/query/results/complete/CompleteResultBuilderBasicValuedConverted.java index 81e23760f394..32e10ae1065a 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/results/complete/CompleteResultBuilderBasicValuedConverted.java +++ b/hibernate-core/src/main/java/org/hibernate/query/results/complete/CompleteResultBuilderBasicValuedConverted.java @@ -9,6 +9,7 @@ import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.metamodel.mapping.BasicValuedMapping; +import org.hibernate.sql.results.graph.Fetchable; import org.hibernate.type.descriptor.converter.internal.JpaAttributeConverterImpl; import org.hibernate.query.results.DomainResultCreationStateImpl; import org.hibernate.query.results.ResultBuilder; @@ -71,7 +72,7 @@ public ResultBuilder cacheKeyInstance() { public BasicResult buildResult( JdbcValuesMetadata jdbcResultsMetadata, int resultPosition, - BiFunction legacyFetchResolver, + BiFunction legacyFetchResolver, DomainResultCreationState domainResultCreationState) { final DomainResultCreationStateImpl creationStateImpl = impl( domainResultCreationState ); final SessionFactoryImplementor sessionFactory = creationStateImpl.getSessionFactory(); diff --git a/hibernate-core/src/main/java/org/hibernate/query/results/complete/CompleteResultBuilderBasicValuedStandard.java b/hibernate-core/src/main/java/org/hibernate/query/results/complete/CompleteResultBuilderBasicValuedStandard.java index bf5db51513de..be41f3783026 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/results/complete/CompleteResultBuilderBasicValuedStandard.java +++ b/hibernate-core/src/main/java/org/hibernate/query/results/complete/CompleteResultBuilderBasicValuedStandard.java @@ -18,6 +18,7 @@ import org.hibernate.sql.ast.spi.SqlExpressionResolver; import org.hibernate.sql.ast.spi.SqlSelection; import org.hibernate.sql.results.graph.DomainResultCreationState; +import org.hibernate.sql.results.graph.Fetchable; import org.hibernate.sql.results.graph.basic.BasicResult; import org.hibernate.sql.results.jdbc.spi.JdbcValuesMetadata; import org.hibernate.type.descriptor.java.JavaType; @@ -67,7 +68,7 @@ public Class getJavaType() { public BasicResult buildResult( JdbcValuesMetadata jdbcResultsMetadata, int resultPosition, - BiFunction legacyFetchResolver, + BiFunction legacyFetchResolver, DomainResultCreationState domainResultCreationState) { final DomainResultCreationStateImpl creationStateImpl = impl( domainResultCreationState ); final SessionFactoryImplementor sessionFactory = creationStateImpl.getSessionFactory(); diff --git a/hibernate-core/src/main/java/org/hibernate/query/results/complete/CompleteResultBuilderCollectionStandard.java b/hibernate-core/src/main/java/org/hibernate/query/results/complete/CompleteResultBuilderCollectionStandard.java index c2a49ff867a2..8ca1f231af5d 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/results/complete/CompleteResultBuilderCollectionStandard.java +++ b/hibernate-core/src/main/java/org/hibernate/query/results/complete/CompleteResultBuilderCollectionStandard.java @@ -24,6 +24,7 @@ import org.hibernate.sql.ast.tree.from.TableGroup; 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.jdbc.spi.JdbcValuesMetadata; import static org.hibernate.query.results.ResultsHelper.impl; @@ -91,7 +92,7 @@ public ResultBuilder cacheKeyInstance() { public DomainResult buildResult( JdbcValuesMetadata jdbcResultsMetadata, int resultPosition, - BiFunction legacyFetchResolver, + BiFunction legacyFetchResolver, DomainResultCreationState domainResultCreationState) { final DomainResultCreationStateImpl creationStateImpl = impl( domainResultCreationState ); final SessionFactoryImplementor sessionFactory = creationStateImpl.getSessionFactory(); diff --git a/hibernate-core/src/main/java/org/hibernate/query/results/complete/CompleteResultBuilderEntityJpa.java b/hibernate-core/src/main/java/org/hibernate/query/results/complete/CompleteResultBuilderEntityJpa.java index c8a57a185567..cec680b1e33f 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/results/complete/CompleteResultBuilderEntityJpa.java +++ b/hibernate-core/src/main/java/org/hibernate/query/results/complete/CompleteResultBuilderEntityJpa.java @@ -21,6 +21,7 @@ import org.hibernate.spi.NavigablePath; import org.hibernate.sql.ast.spi.SqlAliasBase; import org.hibernate.sql.results.graph.DomainResultCreationState; +import org.hibernate.sql.results.graph.Fetchable; import org.hibernate.sql.results.graph.entity.EntityResult; import org.hibernate.sql.results.jdbc.spi.JdbcValuesMetadata; @@ -39,14 +40,14 @@ public class CompleteResultBuilderEntityJpa implements CompleteResultBuilderEnti private final EntityMappingType entityDescriptor; private final LockMode lockMode; private final BasicValuedFetchBuilder discriminatorFetchBuilder; - private final HashMap explicitFetchBuilderMap; + private final HashMap explicitFetchBuilderMap; public CompleteResultBuilderEntityJpa( NavigablePath navigablePath, EntityMappingType entityDescriptor, LockMode lockMode, BasicValuedFetchBuilder discriminatorFetchBuilder, - HashMap explicitFetchBuilderMap) { + HashMap explicitFetchBuilderMap) { this.navigablePath = navigablePath; this.entityDescriptor = entityDescriptor; this.lockMode = lockMode; @@ -87,7 +88,7 @@ public ResultBuilder cacheKeyInstance() { public EntityResult buildResult( JdbcValuesMetadata jdbcResultsMetadata, int resultPosition, - BiFunction legacyFetchResolver, + BiFunction legacyFetchResolver, DomainResultCreationState domainResultCreationState) { final String implicitAlias = entityDescriptor.getSqlAliasStem() + resultPosition; final SqlAliasBase sqlAliasBase = domainResultCreationState.getSqlAliasBaseManager().createSqlAliasBase( implicitAlias ); @@ -139,7 +140,7 @@ public EntityResult buildResult( } @Override - public void visitFetchBuilders(BiConsumer consumer) { + public void visitFetchBuilders(BiConsumer consumer) { explicitFetchBuilderMap.forEach( consumer ); } 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 29fb0c864bbe..01d621db4143 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 @@ -22,6 +22,7 @@ import org.hibernate.query.results.dynamic.DynamicFetchBuilderLegacy; import org.hibernate.sql.ast.spi.SqlAliasBaseConstant; import org.hibernate.sql.results.graph.DomainResultCreationState; +import org.hibernate.sql.results.graph.Fetchable; import org.hibernate.sql.results.graph.entity.EntityResult; import org.hibernate.sql.results.jdbc.spi.JdbcValuesMetadata; @@ -34,7 +35,7 @@ public class CompleteResultBuilderEntityStandard implements CompleteResultBuilde private final EntityMappingType entityDescriptor; private final LockMode lockMode; private final BasicValuedFetchBuilder discriminatorFetchBuilder; - private final HashMap explicitFetchBuilderMap; + private final HashMap explicitFetchBuilderMap; public CompleteResultBuilderEntityStandard( String tableAlias, @@ -42,7 +43,7 @@ public CompleteResultBuilderEntityStandard( EntityMappingType entityDescriptor, LockMode lockMode, BasicValuedFetchBuilder discriminatorFetchBuilder, - HashMap explicitFetchBuilderMap) { + HashMap explicitFetchBuilderMap) { this.tableAlias = tableAlias; this.navigablePath = navigablePath; this.entityDescriptor = entityDescriptor; @@ -120,7 +121,7 @@ public ResultBuilder cacheKeyInstance() { public EntityResult buildResult( JdbcValuesMetadata jdbcResultsMetadata, int resultPosition, - BiFunction legacyFetchResolver, + BiFunction legacyFetchResolver, DomainResultCreationState domainResultCreationState) { final DomainResultCreationStateImpl impl = ResultsHelper.impl( domainResultCreationState ); impl.disallowPositionalSelections(); @@ -169,7 +170,7 @@ public EntityResult buildResult( } @Override - public void visitFetchBuilders(BiConsumer consumer) { + public void visitFetchBuilders(BiConsumer consumer) { explicitFetchBuilderMap.forEach( consumer ); } diff --git a/hibernate-core/src/main/java/org/hibernate/query/results/complete/CompleteResultBuilderInstantiation.java b/hibernate-core/src/main/java/org/hibernate/query/results/complete/CompleteResultBuilderInstantiation.java index 3baac22da8b8..41bdaf7f1fe8 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/results/complete/CompleteResultBuilderInstantiation.java +++ b/hibernate-core/src/main/java/org/hibernate/query/results/complete/CompleteResultBuilderInstantiation.java @@ -14,6 +14,7 @@ import org.hibernate.query.results.ResultBuilder; 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.instantiation.internal.ArgumentDomainResult; import org.hibernate.sql.results.graph.instantiation.internal.DynamicInstantiationResultImpl; import org.hibernate.sql.results.jdbc.spi.JdbcValuesMetadata; @@ -51,7 +52,7 @@ public ResultBuilder cacheKeyInstance() { public DomainResult buildResult( JdbcValuesMetadata jdbcResultsMetadata, int resultPosition, - BiFunction legacyFetchResolver, + BiFunction legacyFetchResolver, DomainResultCreationState domainResultCreationState) { final List> argumentDomainResults = new ArrayList<>( argumentResultBuilders.size() ); diff --git a/hibernate-core/src/main/java/org/hibernate/query/results/complete/DelayedFetchBuilderBasicPart.java b/hibernate-core/src/main/java/org/hibernate/query/results/complete/DelayedFetchBuilderBasicPart.java index 374ded21ae9e..e50b06f88356 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/results/complete/DelayedFetchBuilderBasicPart.java +++ b/hibernate-core/src/main/java/org/hibernate/query/results/complete/DelayedFetchBuilderBasicPart.java @@ -16,6 +16,7 @@ import org.hibernate.query.results.dynamic.DynamicFetchBuilderLegacy; import org.hibernate.sql.results.graph.DomainResultCreationState; import org.hibernate.sql.results.graph.FetchParent; +import org.hibernate.sql.results.graph.Fetchable; import org.hibernate.sql.results.graph.basic.BasicFetch; import org.hibernate.sql.results.jdbc.spi.JdbcValuesMetadata; @@ -57,7 +58,7 @@ public BasicFetch buildFetch( FetchParent parent, NavigablePath fetchPath, JdbcValuesMetadata jdbcResultsMetadata, - BiFunction legacyFetchResolver, + BiFunction legacyFetchResolver, DomainResultCreationState domainResultCreationState) { return new BasicFetch<>( -1, diff --git a/hibernate-core/src/main/java/org/hibernate/query/results/dynamic/AbstractFetchBuilderContainer.java b/hibernate-core/src/main/java/org/hibernate/query/results/dynamic/AbstractFetchBuilderContainer.java index 053e46b5bfda..10d498cbfe19 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/results/dynamic/AbstractFetchBuilderContainer.java +++ b/hibernate-core/src/main/java/org/hibernate/query/results/dynamic/AbstractFetchBuilderContainer.java @@ -11,21 +11,22 @@ import org.hibernate.internal.util.collections.ArrayHelper; import org.hibernate.query.results.FetchBuilder; +import org.hibernate.sql.results.graph.Fetchable; /** * @author Steve Ebersole */ public abstract class AbstractFetchBuilderContainer> implements DynamicFetchBuilderContainer { - private Map fetchBuilderMap; + private Map fetchBuilderMap; protected AbstractFetchBuilderContainer() { } protected AbstractFetchBuilderContainer(AbstractFetchBuilderContainer original) { if ( original.fetchBuilderMap != null ) { - final Map fetchBuilderMap = new HashMap<>( original.fetchBuilderMap.size() ); - for ( Map.Entry entry : original.fetchBuilderMap.entrySet() ) { + final Map fetchBuilderMap = new HashMap<>( original.fetchBuilderMap.size() ); + for ( Map.Entry entry : original.fetchBuilderMap.entrySet() ) { final FetchBuilder fetchBuilder; if ( entry.getValue() instanceof DynamicFetchBuilderStandard ) { fetchBuilder = ( (DynamicFetchBuilderStandard) entry.getValue() ).cacheKeyInstance( this ); @@ -42,40 +43,38 @@ protected AbstractFetchBuilderContainer(AbstractFetchBuilderContainer origina protected abstract String getPropertyBase(); @Override - public FetchBuilder findFetchBuilder(String fetchableName) { - return fetchBuilderMap == null ? null : fetchBuilderMap.get( fetchableName ); + public FetchBuilder findFetchBuilder(Fetchable fetchable) { + return fetchBuilderMap == null ? null : fetchBuilderMap.get( fetchable ); } @Override - public T addProperty(String propertyName, String columnAlias) { - final DynamicFetchBuilder fetchBuilder = addProperty( propertyName ); + public T addProperty(Fetchable fetchable, String columnAlias) { + final DynamicFetchBuilder fetchBuilder = addProperty( fetchable ); fetchBuilder.addColumnAlias( columnAlias ); - return (T) this; } @Override - public T addProperty(String propertyName, String... columnAliases) { - final DynamicFetchBuilder fetchBuilder = addProperty( propertyName ); + public T addProperty(Fetchable fetchable, String... columnAliases) { + final DynamicFetchBuilder fetchBuilder = addProperty( fetchable ); ArrayHelper.forEach( columnAliases, fetchBuilder::addColumnAlias ); - return (T) this; } @Override - public DynamicFetchBuilder addProperty(String propertyName) { + public DynamicFetchBuilder addProperty(Fetchable fetchable) { if ( fetchBuilderMap == null ) { fetchBuilderMap = new HashMap<>(); } else { - final FetchBuilder existing = fetchBuilderMap.get( propertyName ); + final FetchBuilder existing = fetchBuilderMap.get( fetchable ); if ( existing != null ) { throw new IllegalArgumentException( String.format( Locale.ROOT, "Fetch was already defined for %s.%s : %s", getPropertyBase(), - propertyName, + fetchable, existing ) ); @@ -83,19 +82,20 @@ public DynamicFetchBuilder addProperty(String propertyName) { } final DynamicFetchBuilderStandard fetchBuilder = new DynamicFetchBuilderStandard( - propertyName + fetchable ); - fetchBuilderMap.put( propertyName, fetchBuilder ); + fetchBuilderMap.put( fetchable, fetchBuilder ); return fetchBuilder; } - public void addFetchBuilder(String propertyName, FetchBuilder fetchBuilder) { + @Override + public void addFetchBuilder(Fetchable fetchable, FetchBuilder fetchBuilder) { if ( fetchBuilderMap == null ) { fetchBuilderMap = new HashMap<>(); } - fetchBuilderMap.put( propertyName, fetchBuilder ); + fetchBuilderMap.put( fetchable, fetchBuilder ); } @Override diff --git a/hibernate-core/src/main/java/org/hibernate/query/results/dynamic/DynamicFetchBuilderContainer.java b/hibernate-core/src/main/java/org/hibernate/query/results/dynamic/DynamicFetchBuilderContainer.java index ed65d1a425be..c7cfe5566ee9 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/results/dynamic/DynamicFetchBuilderContainer.java +++ b/hibernate-core/src/main/java/org/hibernate/query/results/dynamic/DynamicFetchBuilderContainer.java @@ -5,6 +5,7 @@ package org.hibernate.query.results.dynamic; import org.hibernate.query.results.FetchBuilder; +import org.hibernate.sql.results.graph.Fetchable; /** * @author Steve Ebersole @@ -13,22 +14,22 @@ public interface DynamicFetchBuilderContainer { /** * Locate an explicit fetch definition for the named fetchable */ - FetchBuilder findFetchBuilder(String fetchableName); + FetchBuilder findFetchBuilder(Fetchable fetchable); /** * Add a property mapped to a single column. */ - DynamicFetchBuilderContainer addProperty(String propertyName, String columnAlias); + DynamicFetchBuilderContainer addProperty(Fetchable fetchable, String columnAlias); /** * Add a property mapped to multiple columns */ - DynamicFetchBuilderContainer addProperty(String propertyName, String... columnAliases); + DynamicFetchBuilderContainer addProperty(Fetchable fetchable, String... columnAliases); /** * Add a property whose columns can later be defined using {@link DynamicFetchBuilder#addColumnAlias} */ - DynamicFetchBuilder addProperty(String propertyName); + DynamicFetchBuilder addProperty(Fetchable fetchable); - void addFetchBuilder(String propertyName, FetchBuilder fetchBuilder); + void addFetchBuilder(Fetchable fetchable, FetchBuilder fetchBuilder); } diff --git a/hibernate-core/src/main/java/org/hibernate/query/results/dynamic/DynamicFetchBuilderLegacy.java b/hibernate-core/src/main/java/org/hibernate/query/results/dynamic/DynamicFetchBuilderLegacy.java index 294b6c1f1dd1..d7ce5c7b9566 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/results/dynamic/DynamicFetchBuilderLegacy.java +++ b/hibernate-core/src/main/java/org/hibernate/query/results/dynamic/DynamicFetchBuilderLegacy.java @@ -13,11 +13,14 @@ import org.hibernate.LockMode; import org.hibernate.engine.FetchTiming; -import org.hibernate.metamodel.mapping.AttributeMapping; import org.hibernate.metamodel.mapping.CollectionPart; +import org.hibernate.metamodel.mapping.EntityAssociationMapping; import org.hibernate.metamodel.mapping.ForeignKeyDescriptor; import org.hibernate.metamodel.mapping.PluralAttributeMapping; import org.hibernate.metamodel.mapping.SelectableMapping; +import org.hibernate.metamodel.mapping.ValuedModelPart; +import org.hibernate.metamodel.mapping.internal.EmbeddedAttributeMapping; +import org.hibernate.metamodel.mapping.internal.EntityCollectionPart; import org.hibernate.metamodel.mapping.internal.ToOneAttributeMapping; import org.hibernate.query.NativeQuery; import org.hibernate.query.results.DomainResultCreationStateImpl; @@ -34,6 +37,7 @@ 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.jdbc.spi.JdbcValuesMetadata; import static org.hibernate.query.results.ResultsHelper.impl; @@ -44,16 +48,16 @@ */ public class DynamicFetchBuilderLegacy implements DynamicFetchBuilder, NativeQuery.FetchReturn, DynamicFetchBuilderContainer { - private static final String ELEMENT_PREFIX = CollectionPart.Nature.ELEMENT.getName() + "."; - private static final String INDEX_PREFIX = CollectionPart.Nature.INDEX.getName() + "."; + private static final String ELEMENT_PREFIX = "element."; + private static final int ELEMENT_PREFIX_LENGTH = 8; private final String tableAlias; private final String ownerTableAlias; - private final String fetchableName; + private final Fetchable fetchable; private final List columnNames; - private final Map fetchBuilderMap; + private final Map fetchBuilderMap; private final DynamicResultBuilderEntityStandard resultBuilderEntity; private LockMode lockMode; @@ -61,22 +65,22 @@ public class DynamicFetchBuilderLegacy implements DynamicFetchBuilder, NativeQue public DynamicFetchBuilderLegacy( String tableAlias, String ownerTableAlias, - String fetchableName, + Fetchable fetchable, List columnNames, - Map fetchBuilderMap) { - this( tableAlias, ownerTableAlias, fetchableName, columnNames, fetchBuilderMap, null ); + Map fetchBuilderMap) { + this( tableAlias, ownerTableAlias, fetchable, columnNames, fetchBuilderMap, null ); } public DynamicFetchBuilderLegacy( String tableAlias, String ownerTableAlias, - String fetchableName, + Fetchable fetchable, List columnNames, - Map fetchBuilderMap, + Map fetchBuilderMap, DynamicResultBuilderEntityStandard resultBuilderEntity) { this.tableAlias = tableAlias; this.ownerTableAlias = ownerTableAlias; - this.fetchableName = fetchableName; + this.fetchable = fetchable; this.columnNames = columnNames; this.fetchBuilderMap = fetchBuilderMap; this.resultBuilderEntity = resultBuilderEntity; @@ -92,27 +96,73 @@ public String getOwnerAlias() { return ownerTableAlias; } + @Override + public Fetchable getFetchable() { + return fetchable; + } + @Override public String getFetchableName() { - return fetchableName; + return fetchable.getFetchableName(); + } + + @Override + public NativeQuery.FetchReturn setLockMode(LockMode lockMode) { + this.lockMode = lockMode; + return this; + } + + @Override + public NativeQuery.FetchReturn addProperty(String propertyName, String columnAlias) { + addProperty( resolveFetchable( propertyName ), columnAlias ); + return this; + } + + private Fetchable resolveFetchable(String propertyName) { + if ( fetchable instanceof EntityAssociationMapping attributeMapping ) { + return (Fetchable) attributeMapping.findByPath( propertyName ); + } + else if ( fetchable instanceof PluralAttributeMapping pluralAttributeMapping ) { + if ( propertyName.equals( "key" ) ) { + return pluralAttributeMapping.getIndexDescriptor(); + } + else if ( propertyName.equals( "element" ) ) { + return pluralAttributeMapping.getElementDescriptor().getCollectionAttribute(); + } + else { + final CollectionPart elementDescriptor = pluralAttributeMapping.getElementDescriptor(); + if ( elementDescriptor instanceof EntityCollectionPart entityCollectionPart ) { + if ( propertyName.startsWith( ELEMENT_PREFIX ) ) { + propertyName = propertyName.substring( ELEMENT_PREFIX_LENGTH ); + } + return (Fetchable) entityCollectionPart.getEntityMappingType().findByPath( propertyName ); + } + } + } + throw new UnsupportedOperationException( "Unsupported fetchable type: " + fetchable.getClass().getName() ); + } + + @Override + public NativeQuery.ReturnProperty addProperty(String propertyName) { + return addProperty( resolveFetchable( propertyName ) ); } @Override public DynamicFetchBuilderLegacy cacheKeyInstance() { - final Map fetchBuilderMap; + final Map fetchBuilderMap; if ( this.fetchBuilderMap == null ) { fetchBuilderMap = null; } else { fetchBuilderMap = new HashMap<>( this.fetchBuilderMap.size() ); - for ( Map.Entry entry : this.fetchBuilderMap.entrySet() ) { + for ( Map.Entry entry : this.fetchBuilderMap.entrySet() ) { fetchBuilderMap.put( entry.getKey(), entry.getValue().cacheKeyInstance() ); } } return new DynamicFetchBuilderLegacy( tableAlias, ownerTableAlias, - fetchableName, + fetchable, columnNames == null ? null : List.copyOf( columnNames ), fetchBuilderMap, resultBuilderEntity == null ? null : resultBuilderEntity.cacheKeyInstance() @@ -124,17 +174,17 @@ public Fetch buildFetch( FetchParent parent, NavigablePath fetchPath, JdbcValuesMetadata jdbcResultsMetadata, - BiFunction legacyFetchResolver, + BiFunction legacyFetchResolver, DomainResultCreationState domainResultCreationState) { final DomainResultCreationStateImpl creationState = impl( domainResultCreationState ); final TableGroup ownerTableGroup = creationState.getFromClauseAccess().findByAlias( ownerTableAlias ); - final AttributeMapping attributeMapping = parent.getReferencedMappingContainer() - .findContainingEntityMapping() - .findDeclaredAttributeMapping( fetchableName ); final TableGroup tableGroup; - if ( attributeMapping instanceof TableGroupJoinProducer ) { + if ( lockMode != null ) { + domainResultCreationState.getSqlAstCreationState().registerLockMode( tableAlias, lockMode ); + } + if ( fetchable instanceof TableGroupJoinProducer ) { final SqlAliasBase sqlAliasBase = new SqlAliasBaseConstant( tableAlias ); - final TableGroupJoin tableGroupJoin = ( (TableGroupJoinProducer) attributeMapping ).createTableGroupJoin( + final TableGroupJoin tableGroupJoin = ( (TableGroupJoinProducer) fetchable ).createTableGroupJoin( fetchPath, ownerTableGroup, tableAlias, @@ -151,70 +201,73 @@ public Fetch buildFetch( tableGroup = ownerTableGroup; } - if ( columnNames != null ) { + if ( !columnNames.isEmpty() ) { final ForeignKeyDescriptor keyDescriptor; - if ( attributeMapping instanceof PluralAttributeMapping ) { - final PluralAttributeMapping pluralAttributeMapping = (PluralAttributeMapping) attributeMapping; - keyDescriptor = pluralAttributeMapping.getKeyDescriptor(); + if ( fetchable instanceof EmbeddedAttributeMapping embeddedAttributeMapping ) { + embeddedAttributeMapping.forEachSelectable( + (selectionIndex, selectableMapping) -> + resolveSqlSelection( + columnNames.get( selectionIndex ), + tableGroup.resolveTableReference( + fetchPath, + (ValuedModelPart) selectableMapping, + selectableMapping.getContainingTableExpression() + ), + selectableMapping, + jdbcResultsMetadata, + domainResultCreationState + ) + ); } else { - // Not sure if this fetch builder can also be used with other attribute mappings - assert attributeMapping instanceof ToOneAttributeMapping; + if ( fetchable instanceof PluralAttributeMapping pluralAttributeMapping ) { + keyDescriptor = pluralAttributeMapping.getKeyDescriptor(); + } + else { + // Not sure if this fetch builder can also be used with other attribute mappings + assert fetchable instanceof ToOneAttributeMapping; - final ToOneAttributeMapping toOneAttributeMapping = (ToOneAttributeMapping) attributeMapping; - keyDescriptor = toOneAttributeMapping.getForeignKeyDescriptor(); - } + final ToOneAttributeMapping toOneAttributeMapping = (ToOneAttributeMapping) fetchable; + keyDescriptor = toOneAttributeMapping.getForeignKeyDescriptor(); + } - if ( !columnNames.isEmpty() ) { keyDescriptor.forEachSelectable( - (selectionIndex, selectableMapping) -> { - resolveSqlSelection( - columnNames.get( selectionIndex ), - tableGroup.resolveTableReference( - fetchPath, - keyDescriptor.getKeyPart(), - selectableMapping.getContainingTableExpression() - ), - selectableMapping, - jdbcResultsMetadata, - domainResultCreationState - ); - } + (selectionIndex, selectableMapping) -> + resolveSqlSelection( + columnNames.get( selectionIndex ), + tableGroup.resolveTableReference( + fetchPath, + keyDescriptor.getKeyPart(), + selectableMapping.getContainingTableExpression() + ), + selectableMapping, + jdbcResultsMetadata, + domainResultCreationState + ) ); } - // We process the fetch builder such that it contains a resultBuilderEntity before calling this method in ResultSetMappingProcessor if ( resultBuilderEntity != null ) { return resultBuilderEntity.buildFetch( parent, - attributeMapping, + fetchable, jdbcResultsMetadata, creationState ); } } try { - final Map.Entry currentRelativePath = creationState.getCurrentRelativePath(); - final String prefix; - if ( currentRelativePath == null ) { - prefix = ""; - } - else { - prefix = currentRelativePath.getKey() - .replace( ELEMENT_PREFIX, "" ) - .replace( INDEX_PREFIX, "" ) + "."; - } creationState.pushExplicitFetchMementoResolver( - relativePath -> { - if ( relativePath.startsWith( prefix ) ) { - return findFetchBuilder( relativePath.substring( prefix.length() ) ); + fetchable -> { + if ( fetchable != null ) { + return findFetchBuilder( fetchable ); } return null; } ); return parent.generateFetchableFetch( - attributeMapping, - parent.resolveNavigablePath( attributeMapping ), + fetchable, + parent.resolveNavigablePath( fetchable ), FetchTiming.IMMEDIATE, true, null, @@ -226,6 +279,11 @@ public Fetch buildFetch( } } + @Override + public void visitFetchBuilders(BiConsumer consumer) { + fetchBuilderMap.forEach( consumer ); + } + private void resolveSqlSelection( String columnAlias, TableReference tableReference, @@ -262,32 +320,27 @@ public List getColumnAliases() { } @Override - public NativeQuery.FetchReturn setLockMode(LockMode lockMode) { - this.lockMode = lockMode; - return this; - } - - @Override - public DynamicFetchBuilderLegacy addProperty(String propertyName, String columnAlias) { - addProperty( propertyName ).addColumnAlias( columnAlias ); - return this; + public DynamicFetchBuilder addProperty(Fetchable fetchable) { + DynamicFetchBuilderStandard fetchBuilder = new DynamicFetchBuilderStandard( fetchable ); + fetchBuilderMap.put( fetchable, fetchBuilder ); + return fetchBuilder; } @Override - public DynamicFetchBuilder addProperty(String propertyName) { - DynamicFetchBuilderStandard fetchBuilder = new DynamicFetchBuilderStandard( propertyName ); - fetchBuilderMap.put( propertyName, fetchBuilder ); - return fetchBuilder; + public FetchBuilder findFetchBuilder(Fetchable fetchable) { + return fetchBuilderMap.get( fetchable ); } @Override - public FetchBuilder findFetchBuilder(String fetchableName) { - return fetchBuilderMap.get( fetchableName ); + public DynamicFetchBuilderContainer addProperty(Fetchable fetchable, String columnAlias) { + final DynamicFetchBuilder fetchBuilder = addProperty( fetchable ); + fetchBuilder.addColumnAlias( columnAlias ); + return this; } @Override - public DynamicFetchBuilderContainer addProperty(String propertyName, String... columnAliases) { - final DynamicFetchBuilder fetchBuilder = addProperty( propertyName ); + public DynamicFetchBuilderContainer addProperty(Fetchable fetchable, String... columnAliases) { + final DynamicFetchBuilder fetchBuilder = addProperty( fetchable ); for ( String columnAlias : columnAliases ) { fetchBuilder.addColumnAlias( columnAlias ); } @@ -295,13 +348,8 @@ public DynamicFetchBuilderContainer addProperty(String propertyName, String... c } @Override - public void addFetchBuilder(String propertyName, FetchBuilder fetchBuilder) { - fetchBuilderMap.put( propertyName, fetchBuilder ); - } - - @Override - public void visitFetchBuilders(BiConsumer consumer) { - fetchBuilderMap.forEach( consumer ); + public void addFetchBuilder(Fetchable fetchable, FetchBuilder fetchBuilder) { + fetchBuilderMap.put( fetchable, fetchBuilder ); } @Override @@ -316,7 +364,8 @@ public boolean equals(Object o) { final DynamicFetchBuilderLegacy that = (DynamicFetchBuilderLegacy) o; return tableAlias.equals( that.tableAlias ) && ownerTableAlias.equals( that.ownerTableAlias ) - && fetchableName.equals( that.fetchableName ) + && fetchable.equals( that.fetchable ) + && lockMode.equals( that.lockMode ) && Objects.equals( columnNames, that.columnNames ) && Objects.equals( fetchBuilderMap, that.fetchBuilderMap ) && Objects.equals( resultBuilderEntity, that.resultBuilderEntity ); @@ -326,7 +375,8 @@ public boolean equals(Object o) { public int hashCode() { int result = tableAlias.hashCode(); result = 31 * result + ownerTableAlias.hashCode(); - result = 31 * result + fetchableName.hashCode(); + result = 31 * result + fetchable.hashCode(); + result = 31 * result + lockMode.hashCode(); result = 31 * result + ( columnNames != null ? columnNames.hashCode() : 0 ); result = 31 * result + ( fetchBuilderMap != null ? fetchBuilderMap.hashCode() : 0 ); result = 31 * result + ( resultBuilderEntity != null ? resultBuilderEntity.hashCode() : 0 ); diff --git a/hibernate-core/src/main/java/org/hibernate/query/results/dynamic/DynamicFetchBuilderStandard.java b/hibernate-core/src/main/java/org/hibernate/query/results/dynamic/DynamicFetchBuilderStandard.java index d7be959e1609..54032a636681 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/results/dynamic/DynamicFetchBuilderStandard.java +++ b/hibernate-core/src/main/java/org/hibernate/query/results/dynamic/DynamicFetchBuilderStandard.java @@ -36,30 +36,29 @@ public class DynamicFetchBuilderStandard implements DynamicFetchBuilder, NativeQuery.ReturnProperty { - private final String fetchableName; + private Fetchable fetchable; private final List columnNames; - public DynamicFetchBuilderStandard(String fetchableName) { - this.fetchableName = fetchableName; - this.columnNames = new ArrayList<>(); + public DynamicFetchBuilderStandard(Fetchable fetchable) { + this( fetchable, new ArrayList<>() ); } - private DynamicFetchBuilderStandard(String fetchableName, List columnNames) { - this.fetchableName = fetchableName; + private DynamicFetchBuilderStandard(Fetchable fetchable, List columnNames) { + this.fetchable = fetchable; this.columnNames = columnNames; } @Override public DynamicFetchBuilderStandard cacheKeyInstance() { return new DynamicFetchBuilderStandard( - fetchableName, + fetchable, List.copyOf( columnNames ) ); } public DynamicFetchBuilderStandard cacheKeyInstance(DynamicFetchBuilderContainer container) { return new DynamicFetchBuilderStandard( - fetchableName, + fetchable, List.copyOf( columnNames ) ); } @@ -69,18 +68,16 @@ public Fetch buildFetch( FetchParent parent, NavigablePath fetchPath, JdbcValuesMetadata jdbcResultsMetadata, - BiFunction legacyFetchResolver, + BiFunction legacyFetchResolver, DomainResultCreationState domainResultCreationState) { final DomainResultCreationStateImpl creationStateImpl = ResultsHelper.impl( domainResultCreationState ); final TableGroup ownerTableGroup = creationStateImpl.getFromClauseAccess().getTableGroup( parent.getNavigablePath() ); - - final Fetchable attributeMapping = (Fetchable) parent.getReferencedMappingContainer().findSubPart( fetchableName, null ); final SqlExpressionResolver sqlExpressionResolver = domainResultCreationState.getSqlAstCreationState().getSqlExpressionResolver(); - final BasicValuedModelPart basicPart = attributeMapping.asBasicValuedModelPart(); + final BasicValuedModelPart basicPart = fetchable.asBasicValuedModelPart(); if ( basicPart != null ) { - attributeMapping.forEachSelectable( + fetchable.forEachSelectable( getSelectableConsumer( fetchPath, jdbcResultsMetadata, @@ -92,7 +89,7 @@ public Fetch buildFetch( ) ); return parent.generateFetchableFetch( - attributeMapping, + fetchable, fetchPath, FetchTiming.IMMEDIATE, true, @@ -100,8 +97,8 @@ public Fetch buildFetch( creationStateImpl ); } - else if ( attributeMapping instanceof EmbeddableValuedFetchable ) { - attributeMapping.forEachSelectable( + else if ( fetchable instanceof EmbeddableValuedFetchable embeddableValuedFetchable ) { + fetchable.forEachSelectable( getSelectableConsumer( fetchPath, jdbcResultsMetadata, @@ -109,11 +106,11 @@ else if ( attributeMapping instanceof EmbeddableValuedFetchable ) { creationStateImpl, ownerTableGroup, sqlExpressionResolver, - (EmbeddableValuedFetchable) attributeMapping + embeddableValuedFetchable ) ); return parent.generateFetchableFetch( - attributeMapping, + fetchable, fetchPath, FetchTiming.IMMEDIATE, false, @@ -121,8 +118,7 @@ else if ( attributeMapping instanceof EmbeddableValuedFetchable ) { creationStateImpl ); } - else if ( attributeMapping instanceof ToOneAttributeMapping ) { - final ToOneAttributeMapping toOneAttributeMapping = (ToOneAttributeMapping) attributeMapping; + else if ( fetchable instanceof ToOneAttributeMapping toOneAttributeMapping) { toOneAttributeMapping.getForeignKeyDescriptor().getPart( toOneAttributeMapping.getSideNature() ) .forEachSelectable( getSelectableConsumer( @@ -136,17 +132,17 @@ else if ( attributeMapping instanceof ToOneAttributeMapping ) { ) ); return parent.generateFetchableFetch( - attributeMapping, + fetchable, fetchPath, - attributeMapping.getMappedFetchOptions().getTiming(), + fetchable.getMappedFetchOptions().getTiming(), false, null, creationStateImpl ); } else { - assert attributeMapping instanceof PluralAttributeMapping; - final PluralAttributeMapping pluralAttributeMapping = (PluralAttributeMapping) attributeMapping; + assert fetchable instanceof PluralAttributeMapping : "Expected PluralAttributeMapping fetchable but have " + fetchable + " instead"; + final PluralAttributeMapping pluralAttributeMapping = (PluralAttributeMapping) fetchable; pluralAttributeMapping.getKeyDescriptor().visitTargetSelectables( getSelectableConsumer( fetchPath, @@ -159,9 +155,9 @@ else if ( attributeMapping instanceof ToOneAttributeMapping ) { ) ); return parent.generateFetchableFetch( - attributeMapping, + fetchable, fetchPath, - attributeMapping.getMappedFetchOptions().getTiming(), + fetchable.getMappedFetchOptions().getTiming(), false, null, creationStateImpl @@ -215,7 +211,7 @@ public List getColumnAliases() { @Override public int hashCode() { - int result = fetchableName.hashCode(); + int result = fetchable.hashCode(); result = 31 * result + columnNames.hashCode(); return result; } @@ -230,7 +226,7 @@ public boolean equals(Object o) { } final DynamicFetchBuilderStandard that = (DynamicFetchBuilderStandard) o; - return fetchableName.equals( that.fetchableName ) + return fetchable.equals( that.fetchable ) && columnNames.equals( that.columnNames ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/results/dynamic/DynamicResultBuilderAttribute.java b/hibernate-core/src/main/java/org/hibernate/query/results/dynamic/DynamicResultBuilderAttribute.java index 45d2acc31bd6..4559733dbff0 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/results/dynamic/DynamicResultBuilderAttribute.java +++ b/hibernate-core/src/main/java/org/hibernate/query/results/dynamic/DynamicResultBuilderAttribute.java @@ -16,6 +16,7 @@ import org.hibernate.sql.ast.spi.SqlSelection; 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.basic.BasicResult; import org.hibernate.sql.results.jdbc.spi.JdbcValuesMetadata; @@ -76,7 +77,7 @@ public DynamicResultBuilderAttribute cacheKeyInstance() { public DomainResult buildResult( JdbcValuesMetadata jdbcResultsMetadata, int resultPosition, - BiFunction legacyFetchResolver, + BiFunction legacyFetchResolver, DomainResultCreationState domainResultCreationState) { final DomainResultCreationStateImpl domainResultCreationStateImpl = impl( domainResultCreationState ); diff --git a/hibernate-core/src/main/java/org/hibernate/query/results/dynamic/DynamicResultBuilderBasicConverted.java b/hibernate-core/src/main/java/org/hibernate/query/results/dynamic/DynamicResultBuilderBasicConverted.java index 26f4b95a7f94..629e98f643db 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/results/dynamic/DynamicResultBuilderBasicConverted.java +++ b/hibernate-core/src/main/java/org/hibernate/query/results/dynamic/DynamicResultBuilderBasicConverted.java @@ -11,6 +11,7 @@ import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.metamodel.mapping.BasicValuedMapping; +import org.hibernate.sql.results.graph.Fetchable; import org.hibernate.type.descriptor.converter.internal.JpaAttributeConverterImpl; import org.hibernate.type.descriptor.converter.spi.BasicValueConverter; import org.hibernate.query.results.ResultsHelper; @@ -92,7 +93,7 @@ public DynamicResultBuilderBasicConverted cacheKeyInstance() { public BasicResult buildResult( JdbcValuesMetadata jdbcResultsMetadata, int resultPosition, - BiFunction legacyFetchResolver, + BiFunction legacyFetchResolver, DomainResultCreationState domainResultCreationState) { final TypeConfiguration typeConfiguration = domainResultCreationState.getSqlAstCreationState() .getCreationContext() diff --git a/hibernate-core/src/main/java/org/hibernate/query/results/dynamic/DynamicResultBuilderBasicStandard.java b/hibernate-core/src/main/java/org/hibernate/query/results/dynamic/DynamicResultBuilderBasicStandard.java index eda44a2a8820..54c23696cd47 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/results/dynamic/DynamicResultBuilderBasicStandard.java +++ b/hibernate-core/src/main/java/org/hibernate/query/results/dynamic/DynamicResultBuilderBasicStandard.java @@ -8,6 +8,7 @@ import java.util.function.BiFunction; import org.hibernate.metamodel.mapping.JdbcMapping; +import org.hibernate.sql.results.graph.Fetchable; import org.hibernate.type.descriptor.converter.spi.BasicValueConverter; import org.hibernate.query.NativeQuery; import org.hibernate.engine.spi.SessionFactoryImplementor; @@ -118,7 +119,7 @@ public DynamicResultBuilderBasicStandard cacheKeyInstance() { public BasicResult buildResult( JdbcValuesMetadata jdbcResultsMetadata, int resultPosition, - BiFunction legacyFetchResolver, + BiFunction legacyFetchResolver, DomainResultCreationState domainResultCreationState) { final SessionFactoryImplementor sessionFactory = domainResultCreationState.getSqlAstCreationState() .getCreationContext() diff --git a/hibernate-core/src/main/java/org/hibernate/query/results/dynamic/DynamicResultBuilderEntity.java b/hibernate-core/src/main/java/org/hibernate/query/results/dynamic/DynamicResultBuilderEntity.java index c55715b4d5b1..2eda2b958967 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/results/dynamic/DynamicResultBuilderEntity.java +++ b/hibernate-core/src/main/java/org/hibernate/query/results/dynamic/DynamicResultBuilderEntity.java @@ -8,6 +8,7 @@ import org.hibernate.query.results.ResultBuilderEntityValued; import org.hibernate.sql.results.graph.DomainResultCreationState; +import org.hibernate.sql.results.graph.Fetchable; import org.hibernate.sql.results.graph.entity.EntityResult; import org.hibernate.sql.results.jdbc.spi.JdbcValuesMetadata; @@ -19,6 +20,6 @@ public interface DynamicResultBuilderEntity extends DynamicResultBuilder, Result EntityResult buildResult( JdbcValuesMetadata jdbcResultsMetadata, int resultPosition, - BiFunction legacyFetchResolver, + BiFunction legacyFetchResolver, DomainResultCreationState domainResultCreationState); } diff --git a/hibernate-core/src/main/java/org/hibernate/query/results/dynamic/DynamicResultBuilderEntityCalculated.java b/hibernate-core/src/main/java/org/hibernate/query/results/dynamic/DynamicResultBuilderEntityCalculated.java index c5b4e4837d91..660b2b765267 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/results/dynamic/DynamicResultBuilderEntityCalculated.java +++ b/hibernate-core/src/main/java/org/hibernate/query/results/dynamic/DynamicResultBuilderEntityCalculated.java @@ -15,6 +15,7 @@ import org.hibernate.sql.ast.spi.SqlAliasBaseConstant; import org.hibernate.sql.ast.tree.from.TableGroup; import org.hibernate.sql.results.graph.DomainResultCreationState; +import org.hibernate.sql.results.graph.Fetchable; import org.hibernate.sql.results.graph.entity.EntityResult; import org.hibernate.sql.results.jdbc.spi.JdbcValuesMetadata; @@ -106,7 +107,7 @@ public DynamicResultBuilderEntityCalculated cacheKeyInstance() { public EntityResult buildResult( JdbcValuesMetadata jdbcResultsMetadata, int resultPosition, - BiFunction legacyFetchResolver, + BiFunction legacyFetchResolver, DomainResultCreationState domainResultCreationState) { final DomainResultCreationStateImpl creationStateImpl = ResultsHelper.impl( domainResultCreationState ); diff --git a/hibernate-core/src/main/java/org/hibernate/query/results/dynamic/DynamicResultBuilderEntityStandard.java b/hibernate-core/src/main/java/org/hibernate/query/results/dynamic/DynamicResultBuilderEntityStandard.java index f9a192c49eab..c9f130cbce6d 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/results/dynamic/DynamicResultBuilderEntityStandard.java +++ b/hibernate-core/src/main/java/org/hibernate/query/results/dynamic/DynamicResultBuilderEntityStandard.java @@ -7,7 +7,6 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; -import java.util.Map; import java.util.Objects; import java.util.function.BiFunction; import java.util.function.Function; @@ -15,13 +14,12 @@ import org.hibernate.LockMode; import org.hibernate.engine.FetchTiming; import org.hibernate.metamodel.mapping.CollectionPart; -import org.hibernate.metamodel.mapping.EntityIdentifierMapping; +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.metamodel.mapping.SelectableMapping; import org.hibernate.metamodel.mapping.internal.ManyToManyCollectionPart; -import org.hibernate.metamodel.mapping.internal.SingleAttributeIdentifierMapping; import org.hibernate.query.NativeQuery; import org.hibernate.query.results.DomainResultCreationStateImpl; import org.hibernate.query.results.FetchBuilder; @@ -49,9 +47,6 @@ public class DynamicResultBuilderEntityStandard extends AbstractFetchBuilderContainer implements DynamicResultBuilderEntity, NativeQuery.RootReturn { - private static final String ELEMENT_PREFIX = CollectionPart.Nature.ELEMENT.getName() + "."; - private static final String INDEX_PREFIX = CollectionPart.Nature.INDEX.getName() + "."; - private final NavigablePath navigablePath; private final EntityMappingType entityMapping; @@ -138,7 +133,7 @@ public DynamicResultBuilderEntityStandard cacheKeyInstance() { public EntityResult buildResult( JdbcValuesMetadata jdbcResultsMetadata, int resultPosition, - BiFunction legacyFetchResolver, + BiFunction legacyFetchResolver, DomainResultCreationState domainResultCreationState) { return buildResultOrFetch( (tableGroup) -> (EntityResult) entityMapping.createDomainResult( @@ -268,7 +263,7 @@ else if ( idFetchBuilder != null ) { } if ( discriminatorColumnName != null ) { - resolveSqlSelection( + resolveDiscriminatorSqlSelection( discriminatorColumnName, tableReference, entityMapping.getDiscriminatorMapping(), @@ -278,27 +273,10 @@ else if ( idFetchBuilder != null ) { } try { - final Map.Entry currentRelativePath = creationState.getCurrentRelativePath(); - final String prefix; - if ( currentRelativePath == null ) { - prefix = ""; - } - else { - prefix = currentRelativePath.getKey() - .replace( ELEMENT_PREFIX, "" ) - .replace( INDEX_PREFIX, "" ) + "."; - } creationState.pushExplicitFetchMementoResolver( - relativePath -> { - if ( relativePath.startsWith( prefix ) ) { - final int startIndex; - if ( relativePath.regionMatches( prefix.length(), ELEMENT_PREFIX, 0, ELEMENT_PREFIX.length() ) ) { - startIndex = prefix.length() + ELEMENT_PREFIX.length(); - } - else { - startIndex = prefix.length(); - } - return findFetchBuilder( relativePath.substring( startIndex ) ); + f -> { + if ( f != null ) { + return findFetchBuilder( f ); } return null; } @@ -310,12 +288,27 @@ else if ( idFetchBuilder != null ) { } } + private static void resolveDiscriminatorSqlSelection(String columnAlias, TableReference tableReference, EntityDiscriminatorMapping discriminatorMapping, JdbcValuesMetadata jdbcResultsMetadata, DomainResultCreationState domainResultCreationState) { + final DomainResultCreationStateImpl creationStateImpl = impl( domainResultCreationState ); + creationStateImpl.resolveSqlSelection( + ResultsHelper.resolveSqlExpression( + creationStateImpl, + jdbcResultsMetadata, + tableReference, + discriminatorMapping, + columnAlias + ), + discriminatorMapping.getJdbcMapping().getJdbcJavaType(), + null, + domainResultCreationState.getSqlAstCreationState() + .getCreationContext() + .getSessionFactory() + .getTypeConfiguration() + ); + } + private FetchBuilder findIdFetchBuilder() { - final EntityIdentifierMapping identifierMapping = entityMapping.getIdentifierMapping(); - if ( identifierMapping instanceof SingleAttributeIdentifierMapping ) { - return findFetchBuilder( ( (SingleAttributeIdentifierMapping) identifierMapping ).getAttributeName() ); - } - return findFetchBuilder( identifierMapping.getPartName() ); + return findFetchBuilder( entityMapping.getIdentifierMapping() ); } private void resolveSqlSelection( @@ -354,6 +347,18 @@ public DynamicResultBuilderEntityStandard setDiscriminatorAlias(String columnNam return this; } + @Override + public NativeQuery.RootReturn addProperty(String propertyName, String columnAlias) { + final ModelPart subPart = entityMapping.findSubPart( propertyName ); + addProperty( (Fetchable) subPart, columnAlias ); + return this; + } + + @Override + public NativeQuery.ReturnProperty addProperty(String propertyName) { + return addProperty( (Fetchable) entityMapping.findSubPart( propertyName ) ); + } + @Override public int hashCode() { int result = super.hashCode(); diff --git a/hibernate-core/src/main/java/org/hibernate/query/results/dynamic/DynamicResultBuilderInstantiation.java b/hibernate-core/src/main/java/org/hibernate/query/results/dynamic/DynamicResultBuilderInstantiation.java index 7c353656a23d..66536d222be5 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/results/dynamic/DynamicResultBuilderInstantiation.java +++ b/hibernate-core/src/main/java/org/hibernate/query/results/dynamic/DynamicResultBuilderInstantiation.java @@ -14,6 +14,7 @@ import org.hibernate.query.results.ResultBuilderInstantiationValued; 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.instantiation.internal.ArgumentDomainResult; import org.hibernate.sql.results.graph.instantiation.internal.DynamicInstantiationResultImpl; import org.hibernate.sql.results.jdbc.spi.JdbcValuesMetadata; @@ -104,7 +105,7 @@ public DynamicResultBuilderInstantiation cacheKeyInstance() { public DomainResult buildResult( JdbcValuesMetadata jdbcResultsMetadata, int resultPosition, - BiFunction legacyFetchResolver, + BiFunction legacyFetchResolver, DomainResultCreationState domainResultCreationState) { if ( argumentResultBuilders.isEmpty() ) { throw new IllegalStateException( "DynamicResultBuilderInstantiation defined no arguments" ); diff --git a/hibernate-core/src/main/java/org/hibernate/query/results/dynamic/LegacyFetchResolver.java b/hibernate-core/src/main/java/org/hibernate/query/results/dynamic/LegacyFetchResolver.java index 2e3e9b694c1d..d1e6200ec7bc 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/results/dynamic/LegacyFetchResolver.java +++ b/hibernate-core/src/main/java/org/hibernate/query/results/dynamic/LegacyFetchResolver.java @@ -5,6 +5,7 @@ package org.hibernate.query.results.dynamic; import org.hibernate.query.NativeQuery; +import org.hibernate.sql.results.graph.Fetchable; /** * Contract for handling Hibernate's legacy way of representing fetches through @@ -17,5 +18,5 @@ */ @FunctionalInterface public interface LegacyFetchResolver { - DynamicFetchBuilderLegacy resolve(String ownerTableAlias, String fetchedPartPath); + DynamicFetchBuilderLegacy resolve(String ownerTableAlias, Fetchable fetched); } 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 f8ef557352f2..406ff605942c 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 @@ -21,6 +21,7 @@ import org.hibernate.sql.ast.tree.from.TableGroup; import org.hibernate.sql.results.graph.DomainResultCreationState; import org.hibernate.sql.results.graph.FetchParent; +import org.hibernate.sql.results.graph.Fetchable; import org.hibernate.sql.results.graph.basic.BasicFetch; import org.hibernate.sql.results.jdbc.spi.JdbcValuesMetadata; @@ -42,13 +43,14 @@ public ImplicitFetchBuilderBasic(NavigablePath fetchPath, BasicValuedModelPart f public ImplicitFetchBuilderBasic( NavigablePath fetchPath, - BasicValuedModelPart fetchable, + Fetchable fetchable, + BasicValuedModelPart basicValuedModelPart, DomainResultCreationState creationState) { this.fetchPath = fetchPath; - this.fetchable = fetchable; + this.fetchable = basicValuedModelPart; final DomainResultCreationStateImpl creationStateImpl = impl( creationState ); - final Function fetchBuilderResolver = creationStateImpl.getCurrentExplicitFetchMementoResolver(); - this.fetchBuilder = fetchBuilderResolver.apply( fetchable.getFetchableName() ); + final Function fetchBuilderResolver = creationStateImpl.getCurrentExplicitFetchMementoResolver(); + this.fetchBuilder = fetchBuilderResolver.apply( fetchable ); } @Override @@ -61,7 +63,7 @@ public BasicFetch buildFetch( FetchParent parent, NavigablePath fetchPath, JdbcValuesMetadata jdbcResultsMetadata, - BiFunction legacyFetchResolver, + BiFunction legacyFetchResolver, DomainResultCreationState domainResultCreationState) { if ( fetchBuilder != null ) { return (BasicFetch) fetchBuilder.buildFetch( @@ -145,9 +147,9 @@ public int hashCode() { } @Override - public void visitFetchBuilders(BiConsumer consumer) { + public void visitFetchBuilders(BiConsumer consumer) { if ( fetchBuilder != null ) { - consumer.accept( fetchPath.getLocalName(), fetchBuilder ); + consumer.accept( fetchable, fetchBuilder ); } } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/results/implicit/ImplicitFetchBuilderDiscriminatedAssociation.java b/hibernate-core/src/main/java/org/hibernate/query/results/implicit/ImplicitFetchBuilderDiscriminatedAssociation.java index bedb1ffa8956..c0b2b7341903 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/results/implicit/ImplicitFetchBuilderDiscriminatedAssociation.java +++ b/hibernate-core/src/main/java/org/hibernate/query/results/implicit/ImplicitFetchBuilderDiscriminatedAssociation.java @@ -17,6 +17,7 @@ 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.jdbc.spi.JdbcValuesMetadata; import static org.hibernate.query.results.ResultsHelper.impl; @@ -43,7 +44,7 @@ public Fetch buildFetch( FetchParent parent, NavigablePath fetchPath, JdbcValuesMetadata jdbcResultsMetadata, - BiFunction legacyFetchResolver, + BiFunction legacyFetchResolver, DomainResultCreationState creationState) { final DomainResultCreationStateImpl creationStateImpl = impl( creationState ); 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 a87bec2df4ac..265a01ab7b34 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 @@ -36,7 +36,7 @@ public class ImplicitFetchBuilderEmbeddable implements ImplicitFetchBuilder { private final NavigablePath fetchPath; private final EmbeddableValuedFetchable fetchable; - private final Map fetchBuilders; + private final Map fetchBuilders; public ImplicitFetchBuilderEmbeddable( NavigablePath fetchPath, @@ -45,22 +45,20 @@ public ImplicitFetchBuilderEmbeddable( this.fetchPath = fetchPath; this.fetchable = fetchable; final DomainResultCreationStateImpl creationStateImpl = impl( creationState ); - final Map.Entry relativePath = creationStateImpl.getCurrentRelativePath(); - final Function fetchBuilderResolver = creationStateImpl.getCurrentExplicitFetchMementoResolver(); + final Function fetchBuilderResolver = creationStateImpl.getCurrentExplicitFetchMementoResolver(); final int size = fetchable.getNumberOfFetchables(); - final Map fetchBuilders = CollectionHelper.linkedMapOfSize( size ); + final Map fetchBuilders = CollectionHelper.linkedMapOfSize( size ); for ( int i = 0; i < size; i++ ) { final Fetchable subFetchable = fetchable.getFetchable( i ); - final NavigablePath subFetchPath = relativePath.getValue().append( subFetchable.getFetchableName() ); - final FetchBuilder explicitFetchBuilder = fetchBuilderResolver.apply( subFetchPath.getFullPath() ); + final FetchBuilder explicitFetchBuilder = fetchBuilderResolver.apply( subFetchable ); if ( explicitFetchBuilder == null ) { fetchBuilders.put( - subFetchPath, + subFetchable, Builders.implicitFetchBuilder( fetchPath, subFetchable, creationStateImpl ) ); } else { - fetchBuilders.put( subFetchPath, explicitFetchBuilder ); + fetchBuilders.put( subFetchable, explicitFetchBuilder ); } } this.fetchBuilders = fetchBuilders; @@ -69,13 +67,13 @@ public ImplicitFetchBuilderEmbeddable( private ImplicitFetchBuilderEmbeddable(ImplicitFetchBuilderEmbeddable original) { this.fetchPath = original.fetchPath; this.fetchable = original.fetchable; - final Map fetchBuilders; + final Map fetchBuilders; if ( original.fetchBuilders.isEmpty() ) { fetchBuilders = Collections.emptyMap(); } else { fetchBuilders = new HashMap<>( original.fetchBuilders.size() ); - for ( Map.Entry entry : original.fetchBuilders.entrySet() ) { + for ( Map.Entry entry : original.fetchBuilders.entrySet() ) { fetchBuilders.put( entry.getKey(), entry.getValue().cacheKeyInstance() ); } } @@ -92,7 +90,7 @@ public Fetch buildFetch( FetchParent parent, NavigablePath fetchPath, JdbcValuesMetadata jdbcResultsMetadata, - BiFunction legacyFetchResolver, + BiFunction legacyFetchResolver, DomainResultCreationState creationState) { final DomainResultCreationStateImpl creationStateImpl = impl( creationState ); @@ -168,7 +166,7 @@ public String toString() { } @Override - public void visitFetchBuilders(BiConsumer consumer) { - fetchBuilders.forEach( (k, v) -> consumer.accept( k.getLocalName(), v ) ); + public void visitFetchBuilders(BiConsumer consumer) { + fetchBuilders.forEach( (k, v) -> consumer.accept( k, v ) ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/results/implicit/ImplicitFetchBuilderEntity.java b/hibernate-core/src/main/java/org/hibernate/query/results/implicit/ImplicitFetchBuilderEntity.java index 6e6917cfc7e9..48d560a56a65 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/results/implicit/ImplicitFetchBuilderEntity.java +++ b/hibernate-core/src/main/java/org/hibernate/query/results/implicit/ImplicitFetchBuilderEntity.java @@ -36,7 +36,7 @@ public class ImplicitFetchBuilderEntity implements ImplicitFetchBuilder { private final NavigablePath fetchPath; private final ToOneAttributeMapping fetchable; - private final Map fetchBuilders; + private final Map fetchBuilders; public ImplicitFetchBuilderEntity( NavigablePath fetchPath, @@ -45,26 +45,25 @@ public ImplicitFetchBuilderEntity( this.fetchPath = fetchPath; this.fetchable = fetchable; final DomainResultCreationStateImpl creationStateImpl = impl( creationState ); - final Map.Entry relativePath = creationStateImpl.getCurrentRelativePath(); - final Function fetchBuilderResolver = creationStateImpl.getCurrentExplicitFetchMementoResolver(); + final Function fetchBuilderResolver = creationStateImpl.getCurrentExplicitFetchMementoResolver(); ForeignKeyDescriptor foreignKeyDescriptor = fetchable.getForeignKeyDescriptor(); final String associationKeyPropertyName; - final NavigablePath associationKeyFetchPath; + final Fetchable associationKey; if ( fetchable.getReferencedPropertyName() == null ) { associationKeyPropertyName = fetchable.getEntityMappingType().getIdentifierMapping().getPartName(); - associationKeyFetchPath = relativePath.getValue().append( associationKeyPropertyName ); + associationKey = (Fetchable) fetchable.findSubPart( associationKeyPropertyName ); } else { associationKeyPropertyName = fetchable.getReferencedPropertyName(); - NavigablePath path = relativePath.getValue(); + String keyName = associationKeyPropertyName; for ( String part : StringHelper.split( ".", associationKeyPropertyName ) ) { - path = path.append( part ); + keyName = part; } - associationKeyFetchPath = path; + associationKey = (Fetchable) fetchable.findSubPart( keyName ); } final FetchBuilder explicitAssociationKeyFetchBuilder = fetchBuilderResolver - .apply( relativePath.getKey() + "." + associationKeyPropertyName ); - final Map fetchBuilders; + .apply( fetchable ); + final Map fetchBuilders; if ( explicitAssociationKeyFetchBuilder == null ) { final MappingType partMappingType = foreignKeyDescriptor.getPartMappingType(); if ( partMappingType instanceof EmbeddableMappingType ) { @@ -73,16 +72,15 @@ public ImplicitFetchBuilderEntity( fetchBuilders = CollectionHelper.linkedMapOfSize( size ); for ( int i = 0; i < size; i++ ) { final Fetchable subFetchable = embeddableValuedModelPart.getFetchable( i ); - final NavigablePath subFetchPath = associationKeyFetchPath.append( subFetchable.getFetchableName() ); - final FetchBuilder explicitFetchBuilder = fetchBuilderResolver.apply( subFetchPath.getFullPath() ); + final FetchBuilder explicitFetchBuilder = fetchBuilderResolver.apply( subFetchable ); if ( explicitFetchBuilder == null ) { fetchBuilders.put( - subFetchPath, + subFetchable, Builders.implicitFetchBuilder( fetchPath, subFetchable, creationStateImpl ) ); } else { - fetchBuilders.put( subFetchPath, explicitFetchBuilder ); + fetchBuilders.put( subFetchable, explicitFetchBuilder ); } } } @@ -91,7 +89,7 @@ public ImplicitFetchBuilderEntity( } } else { - fetchBuilders = Collections.singletonMap( associationKeyFetchPath, explicitAssociationKeyFetchBuilder ); + fetchBuilders = Collections.singletonMap( associationKey, explicitAssociationKeyFetchBuilder ); } this.fetchBuilders = fetchBuilders; } @@ -99,13 +97,13 @@ public ImplicitFetchBuilderEntity( private ImplicitFetchBuilderEntity(ImplicitFetchBuilderEntity original) { this.fetchPath = original.fetchPath; this.fetchable = original.fetchable; - final Map fetchBuilders; + final Map fetchBuilders; if ( original.fetchBuilders.isEmpty() ) { fetchBuilders = Collections.emptyMap(); } else { fetchBuilders = new HashMap<>( original.fetchBuilders.size() ); - for ( Map.Entry entry : original.fetchBuilders.entrySet() ) { + for ( Map.Entry entry : original.fetchBuilders.entrySet() ) { fetchBuilders.put( entry.getKey(), entry.getValue().cacheKeyInstance() ); } } @@ -122,7 +120,7 @@ public Fetch buildFetch( FetchParent parent, NavigablePath fetchPath, JdbcValuesMetadata jdbcResultsMetadata, - BiFunction legacyFetchResolver, + BiFunction legacyFetchResolver, DomainResultCreationState creationState) { final Fetch fetch = parent.generateFetchableFetch( fetchable, @@ -147,8 +145,8 @@ public Fetch buildFetch( } @Override - public void visitFetchBuilders(BiConsumer consumer) { - fetchBuilders.forEach( (k, v) -> consumer.accept( k.getLocalName(), v ) ); + public void visitFetchBuilders(BiConsumer consumer) { + fetchBuilders.forEach( (k, v) -> consumer.accept( k, v ) ); } @Override diff --git a/hibernate-core/src/main/java/org/hibernate/query/results/implicit/ImplicitFetchBuilderEntityPart.java b/hibernate-core/src/main/java/org/hibernate/query/results/implicit/ImplicitFetchBuilderEntityPart.java index 86f54f5a97d8..4fe1dac95e4b 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/results/implicit/ImplicitFetchBuilderEntityPart.java +++ b/hibernate-core/src/main/java/org/hibernate/query/results/implicit/ImplicitFetchBuilderEntityPart.java @@ -14,6 +14,7 @@ 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.jdbc.spi.JdbcValuesMetadata; /** @@ -38,7 +39,7 @@ public Fetch buildFetch( FetchParent parent, NavigablePath fetchPath, JdbcValuesMetadata jdbcResultsMetadata, - BiFunction legacyFetchResolver, + BiFunction legacyFetchResolver, DomainResultCreationState creationState) { return parent.generateFetchableFetch( fetchable, diff --git a/hibernate-core/src/main/java/org/hibernate/query/results/implicit/ImplicitFetchBuilderPlural.java b/hibernate-core/src/main/java/org/hibernate/query/results/implicit/ImplicitFetchBuilderPlural.java index b69969368d1b..0478fd02b21a 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/results/implicit/ImplicitFetchBuilderPlural.java +++ b/hibernate-core/src/main/java/org/hibernate/query/results/implicit/ImplicitFetchBuilderPlural.java @@ -13,6 +13,7 @@ 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.jdbc.spi.JdbcValuesMetadata; @@ -41,7 +42,7 @@ public Fetch buildFetch( FetchParent parent, NavigablePath fetchPath, JdbcValuesMetadata jdbcResultsMetadata, - BiFunction legacyFetchResolver, + BiFunction legacyFetchResolver, DomainResultCreationState creationState) { final Fetch fetch = parent.generateFetchableFetch( diff --git a/hibernate-core/src/main/java/org/hibernate/query/results/implicit/ImplicitModelPartResultBuilderBasic.java b/hibernate-core/src/main/java/org/hibernate/query/results/implicit/ImplicitModelPartResultBuilderBasic.java index 831ac01a3392..d1939eb228a1 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/results/implicit/ImplicitModelPartResultBuilderBasic.java +++ b/hibernate-core/src/main/java/org/hibernate/query/results/implicit/ImplicitModelPartResultBuilderBasic.java @@ -15,6 +15,7 @@ import org.hibernate.query.results.dynamic.DynamicFetchBuilderLegacy; import org.hibernate.sql.ast.tree.from.TableGroup; import org.hibernate.sql.results.graph.DomainResultCreationState; +import org.hibernate.sql.results.graph.Fetchable; import org.hibernate.sql.results.graph.basic.BasicResult; import org.hibernate.sql.results.jdbc.spi.JdbcValuesMetadata; @@ -45,7 +46,7 @@ public ResultBuilder cacheKeyInstance() { public BasicResult buildResult( JdbcValuesMetadata jdbcResultsMetadata, int resultPosition, - BiFunction legacyFetchResolver, + BiFunction legacyFetchResolver, DomainResultCreationState domainResultCreationState) { final DomainResultCreationStateImpl creationStateImpl = ResultsHelper.impl( domainResultCreationState ); diff --git a/hibernate-core/src/main/java/org/hibernate/query/results/implicit/ImplicitModelPartResultBuilderEmbeddable.java b/hibernate-core/src/main/java/org/hibernate/query/results/implicit/ImplicitModelPartResultBuilderEmbeddable.java index d3e8009f2e75..a00b5dd7ed75 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/results/implicit/ImplicitModelPartResultBuilderEmbeddable.java +++ b/hibernate-core/src/main/java/org/hibernate/query/results/implicit/ImplicitModelPartResultBuilderEmbeddable.java @@ -17,6 +17,7 @@ import org.hibernate.sql.ast.tree.from.TableGroup; import org.hibernate.sql.ast.tree.from.TableGroupJoin; import org.hibernate.sql.results.graph.DomainResultCreationState; +import org.hibernate.sql.results.graph.Fetchable; import org.hibernate.sql.results.graph.embeddable.EmbeddableResult; import org.hibernate.sql.results.jdbc.spi.JdbcValuesMetadata; @@ -50,7 +51,7 @@ public ResultBuilder cacheKeyInstance() { public EmbeddableResult buildResult( JdbcValuesMetadata jdbcResultsMetadata, int resultPosition, - BiFunction legacyFetchResolver, + BiFunction legacyFetchResolver, DomainResultCreationState domainResultCreationState) { final DomainResultCreationStateImpl creationStateImpl = ResultsHelper.impl( domainResultCreationState ); creationStateImpl.disallowPositionalSelections(); diff --git a/hibernate-core/src/main/java/org/hibernate/query/results/implicit/ImplicitModelPartResultBuilderEntity.java b/hibernate-core/src/main/java/org/hibernate/query/results/implicit/ImplicitModelPartResultBuilderEntity.java index acd92e69fa44..aa6b31fa313c 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/results/implicit/ImplicitModelPartResultBuilderEntity.java +++ b/hibernate-core/src/main/java/org/hibernate/query/results/implicit/ImplicitModelPartResultBuilderEntity.java @@ -16,6 +16,7 @@ import org.hibernate.query.results.dynamic.DynamicFetchBuilderLegacy; import org.hibernate.sql.ast.tree.from.TableGroup; import org.hibernate.sql.results.graph.DomainResultCreationState; +import org.hibernate.sql.results.graph.Fetchable; import org.hibernate.sql.results.graph.entity.EntityResult; import org.hibernate.sql.results.jdbc.spi.JdbcValuesMetadata; @@ -53,7 +54,7 @@ public ResultBuilder cacheKeyInstance() { public EntityResult buildResult( JdbcValuesMetadata jdbcResultsMetadata, int resultPosition, - BiFunction legacyFetchResolver, + BiFunction legacyFetchResolver, DomainResultCreationState domainResultCreationState) { final DomainResultCreationStateImpl creationStateImpl = ResultsHelper.impl( domainResultCreationState ); creationStateImpl.disallowPositionalSelections(); diff --git a/hibernate-core/src/main/java/org/hibernate/query/results/implicit/ImplicitResultClassBuilder.java b/hibernate-core/src/main/java/org/hibernate/query/results/implicit/ImplicitResultClassBuilder.java index 945c9a82ea47..16bbb5bcbc04 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/results/implicit/ImplicitResultClassBuilder.java +++ b/hibernate-core/src/main/java/org/hibernate/query/results/implicit/ImplicitResultClassBuilder.java @@ -15,6 +15,7 @@ import org.hibernate.sql.ast.spi.SqlSelection; 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.basic.BasicResult; import org.hibernate.sql.results.jdbc.spi.JdbcValuesMetadata; import org.hibernate.type.BasicType; @@ -39,7 +40,7 @@ public ImplicitResultClassBuilder(Class suppliedResultClass) { public DomainResult buildResult( JdbcValuesMetadata jdbcResultsMetadata, int resultPosition, - BiFunction legacyFetchResolver, + BiFunction legacyFetchResolver, DomainResultCreationState domainResultCreationState) { assert resultPosition == 0; diff --git a/hibernate-core/src/main/java/org/hibernate/query/sql/internal/NativeQueryImpl.java b/hibernate-core/src/main/java/org/hibernate/query/sql/internal/NativeQueryImpl.java index 691252daa6ad..bb55fb232d95 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sql/internal/NativeQueryImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sql/internal/NativeQueryImpl.java @@ -10,6 +10,7 @@ import java.util.Collection; import java.util.Collections; import java.util.Date; +import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Locale; @@ -20,6 +21,12 @@ import org.hibernate.CacheMode; import org.hibernate.FlushMode; +import org.hibernate.metamodel.mapping.EntityAssociationMapping; +import org.hibernate.metamodel.mapping.EntityMappingType; +import org.hibernate.metamodel.mapping.MappingType; +import org.hibernate.metamodel.mapping.ModelPart; +import org.hibernate.metamodel.mapping.PluralAttributeMapping; +import org.hibernate.metamodel.mapping.internal.EmbeddedAttributeMapping; import org.hibernate.query.QueryFlushMode; import org.hibernate.HibernateException; import org.hibernate.LockMode; @@ -90,6 +97,7 @@ import org.hibernate.query.sql.spi.SelectInterpretationsKey; import org.hibernate.sql.exec.internal.CallbackImpl; import org.hibernate.sql.exec.spi.Callback; +import org.hibernate.sql.results.graph.Fetchable; import org.hibernate.sql.results.jdbc.spi.JdbcValuesMappingProducer; import org.hibernate.sql.results.spi.SingleResultConsumer; import org.hibernate.transform.ResultTransformer; @@ -127,6 +135,7 @@ public class NativeQueryImpl private final ResultSetMapping resultSetMapping; private final boolean resultMappingSuppliedToCtor; + private final HashMap entityMappingTypeByTableAlias = new HashMap<>(); private final QueryOptionsImpl queryOptions = new QueryOptionsImpl(); @@ -1044,6 +1053,7 @@ public DynamicResultBuilderEntityStandard addRoot(String tableAlias, String enti getSessionFactory() ); resultSetMapping.addResultBuilder( resultBuilder ); + entityMappingTypeByTableAlias.put( tableAlias, resultBuilder.getEntityMapping() ); return resultBuilder; } @@ -1059,13 +1069,19 @@ public NativeQueryImplementor addEntity(String entityName) { @Override public NativeQueryImplementor addEntity(String tableAlias, String entityName) { - registerBuilder( Builders.entityCalculated( tableAlias, entityName, getSessionFactory() ) ); + final DynamicResultBuilderEntityCalculated builder = Builders.entityCalculated( tableAlias, entityName, + getSessionFactory() ); + entityMappingTypeByTableAlias.put( tableAlias, builder.getEntityMapping() ); + registerBuilder( builder ); return this; } @Override public NativeQueryImplementor addEntity(String tableAlias, String entityName, LockMode lockMode) { - registerBuilder( Builders.entityCalculated( tableAlias, entityName, lockMode, getSessionFactory() ) ); + final DynamicResultBuilderEntityCalculated builder = Builders.entityCalculated( tableAlias, entityName, lockMode, + getSessionFactory() ); + entityMappingTypeByTableAlias.put( tableAlias, builder.getEntityMapping() ); + registerBuilder( builder ); return this; } @@ -1091,11 +1107,29 @@ public NativeQueryImplementor addEntity(String tableAlias, @SuppressWarnings( @Override public FetchReturn addFetch(String tableAlias, String ownerTableAlias, String joinPropertyName) { - final DynamicFetchBuilderLegacy fetchBuilder = Builders.fetch( tableAlias, ownerTableAlias, joinPropertyName ); + final ModelPart subPart = entityMappingTypeByTableAlias.get( ownerTableAlias ).findSubPart( joinPropertyName ); + addEntityMappingType( tableAlias, subPart ); + final DynamicFetchBuilderLegacy fetchBuilder = Builders.fetch( tableAlias, ownerTableAlias, (Fetchable) subPart ); resultSetMapping.addLegacyFetchBuilder( fetchBuilder ); return fetchBuilder; } + private void addEntityMappingType(String tableAlias, ModelPart part) { + if ( part instanceof PluralAttributeMapping pluralAttributeMapping ) { + final MappingType partMappingType = pluralAttributeMapping.getElementDescriptor() + .getPartMappingType(); + if ( partMappingType instanceof EntityMappingType entityMappingType ) { + entityMappingTypeByTableAlias.put( tableAlias, entityMappingType ); + } + } + else if ( part instanceof EntityAssociationMapping entityAssociationMapping ) { + entityMappingTypeByTableAlias.put( tableAlias, entityAssociationMapping.asEntityMappingType() ); + } + else if ( part instanceof EmbeddedAttributeMapping ) { + throw new UnsupportedOperationException(); + } + } + @Override public NativeQueryImplementor addJoin(String tableAlias, String path) { createFetchJoin( tableAlias, path ); diff --git a/hibernate-core/src/main/java/org/hibernate/query/sql/internal/ResultSetMappingProcessor.java b/hibernate-core/src/main/java/org/hibernate/query/sql/internal/ResultSetMappingProcessor.java index fc3f76a0a2a9..35222df2dd47 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sql/internal/ResultSetMappingProcessor.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sql/internal/ResultSetMappingProcessor.java @@ -21,11 +21,12 @@ import org.hibernate.internal.CoreMessageLogger; import org.hibernate.internal.util.collections.ArrayHelper; import org.hibernate.loader.internal.AliasConstantsHelper; -import org.hibernate.metamodel.mapping.CollectionPart; import org.hibernate.metamodel.mapping.EntityMappingType; +import org.hibernate.metamodel.mapping.PluralAttributeMapping; import org.hibernate.metamodel.mapping.internal.ToOneAttributeMapping; import org.hibernate.persister.collection.CollectionPersister; import org.hibernate.persister.entity.EntityPersister; +import org.hibernate.persister.entity.SingleTableEntityPersister; import org.hibernate.query.NativeQuery; import org.hibernate.query.results.FetchBuilder; import org.hibernate.query.results.ResultSetMapping; @@ -34,6 +35,7 @@ import org.hibernate.query.results.dynamic.DynamicFetchBuilderLegacy; import org.hibernate.query.results.dynamic.DynamicResultBuilderEntityStandard; import org.hibernate.spi.NavigablePath; +import org.hibernate.sql.results.graph.Fetchable; import org.hibernate.type.CollectionType; import org.hibernate.type.ComponentType; import org.hibernate.type.EntityType; @@ -134,7 +136,7 @@ else if ( resultBuilder instanceof NativeQuery.CollectionReturn ) { return this; } - private void processFetchBuilder(String attributeName, FetchBuilder fetchBuilder) { + private void processFetchBuilder(Fetchable attributeName, FetchBuilder fetchBuilder) { if ( fetchBuilder instanceof DynamicFetchBuilderLegacy ) { resultSetMapping.addLegacyFetchBuilder( (DynamicFetchBuilderLegacy) fetchBuilder ); } @@ -234,7 +236,7 @@ private void applyFetchBuilder( final EntityPersister loadable = alias2Persister.get( fetchBuilder.getOwnerAlias() ); final List columnNames; final String[] columnAliases = loadable.getSubclassPropertyColumnAliases( - fetchBuilder.getFetchableName(), + fetchBuilder.getFetchable().getFetchableName(), alias2Suffix.get( fetchBuilder.getOwnerAlias() ) ); if ( columnAliases.length == 0 ) { @@ -248,7 +250,7 @@ private void applyFetchBuilder( columnNames = Arrays.asList( keyColumnAliases ); if ( collectionPersister.hasIndex() ) { resultBuilderEntity.addProperty( - CollectionPart.Nature.INDEX.getName(), + ((PluralAttributeMapping) fetchBuilder.getFetchable()).getIndexDescriptor(), collectionPersister.getIndexColumnAliases( collectionSuffix ) ); } @@ -258,11 +260,11 @@ private void applyFetchBuilder( columnNames = Arrays.asList( columnAliases ); } ownerBuilder.addFetchBuilder( - fetchBuilder.getFetchableName(), + fetchBuilder.getFetchable(), new DynamicFetchBuilderLegacy( fetchBuilder.getTableAlias(), fetchBuilder.getOwnerAlias(), - fetchBuilder.getFetchableName(), + fetchBuilder.getFetchable(), columnNames, Collections.emptyMap(), resultBuilderEntity @@ -277,11 +279,11 @@ private NavigablePath determineNavigablePath(DynamicFetchBuilderLegacy fetchBuil final NativeQuery.ResultNode ownerResult = alias2Return.get( fetchBuilder.getOwnerAlias() ); if ( ownerResult instanceof NativeQuery.RootReturn ) { return ( (NativeQuery.RootReturn) ownerResult ).getNavigablePath() - .append( fetchBuilder.getFetchableName() ); + .append( fetchBuilder.getFetchable().getFetchableName() ); } else { return determineNavigablePath( ( DynamicFetchBuilderLegacy) ownerResult ) - .append( fetchBuilder.getFetchableName() ); + .append( fetchBuilder.getFetchable().getFetchableName() ); } } @@ -315,28 +317,33 @@ private DynamicResultBuilderEntityStandard createSuffixedResultBuilder( resultBuilderEntity.addIdColumnAliases( identifierAliases ); resultBuilderEntity.setDiscriminatorAlias( loadable.getDiscriminatorAlias( suffix ) ); if ( loadable.hasIdentifierProperty() ) { - resultBuilderEntity.addProperty( loadable.getIdentifierPropertyName(), identifierAliases ); + resultBuilderEntity.addProperty( loadable.getIdentifierMapping(), identifierAliases ); } - final String[] propertyNames = loadable.getPropertyNames(); - for ( int i = 0; i < propertyNames.length; i++ ) { - if ( !loadable.isPropertySelectable( i ) ) { - continue; - } - final String propertyName = propertyNames[i]; - final String[] columnAliases = loadable.getSubclassPropertyColumnAliases( propertyName, suffix ); - final Type propertyType = loadable.getPropertyType( propertyName ); - addFetchBuilder( - suffix, - loadable, - resultBuilderEntity, - tableAlias, - identifierAliases, - propertyName, - columnAliases, - propertyType - ); - } + loadable.visitFetchables( + (index, fetchable) -> { + if ( fetchable.isSelectable() ) { + final Type propertyType; + if ( loadable instanceof SingleTableEntityPersister singleTableEntityPersister ) { + propertyType = singleTableEntityPersister.getSubclassPropertyType( index ); + } + else { + propertyType = loadable.getPropertyType( fetchable.getFetchableName() ); + } + addFetchBuilder( + suffix, + loadable, + resultBuilderEntity, + tableAlias, + identifierAliases, + fetchable, + loadable.getSubclassPropertyColumnAliases( fetchable.getFetchableName(), suffix ), + propertyType + ); + } + }, + null + ); return resultBuilderEntity; } @@ -346,7 +353,7 @@ private void addFetchBuilder( DynamicFetchBuilderContainer resultBuilderEntity, String tableAlias, String[] identifierAliases, - String propertyName, + Fetchable fetchable, String[] columnAliases, Type propertyType) { if ( propertyType instanceof CollectionType ) { @@ -361,15 +368,15 @@ private void addFetchBuilder( suffix ); } - resultBuilderEntity.addProperty( propertyName, keyColumnAliases ); + resultBuilderEntity.addProperty( fetchable, keyColumnAliases ); } else if ( propertyType instanceof ComponentType ) { - final Map fetchBuilderMap = new HashMap<>(); + final Map fetchBuilderMap = new HashMap<>(); final DynamicFetchBuilderLegacy fetchBuilder = new DynamicFetchBuilderLegacy( "", tableAlias, - propertyName, - null, + fetchable, + Arrays.asList( columnAliases ), fetchBuilderMap ); final ComponentType componentType = (ComponentType) propertyType; @@ -384,28 +391,28 @@ else if ( propertyType instanceof ComponentType ) { fetchBuilder, tableAlias, identifierAliases, - propertyNames[i], + fetchable, ArrayHelper.slice( columnAliases, aliasIndex, columnSpan ), propertyTypes[i] ); aliasIndex += columnSpan; } - resultBuilderEntity.addFetchBuilder( propertyName, fetchBuilder ); + resultBuilderEntity.addFetchBuilder( fetchable, fetchBuilder ); } else if ( columnAliases.length != 0 ) { if ( propertyType instanceof EntityType ) { - final ToOneAttributeMapping toOne = (ToOneAttributeMapping) loadable.findAttributeMapping( propertyName ); + final ToOneAttributeMapping toOne = (ToOneAttributeMapping) fetchable; if ( !toOne.getIdentifyingColumnsTableExpression().equals( loadable.getTableName() ) ) { // The to-one has a join-table, use the plain join column name instead of the alias assert columnAliases.length == 1; final String[] targetAliases = new String[1]; targetAliases[0] = toOne.getTargetKeyPropertyName(); - resultBuilderEntity.addProperty( propertyName, targetAliases ); + resultBuilderEntity.addProperty( fetchable, targetAliases ); return; } } - resultBuilderEntity.addProperty( propertyName, columnAliases ); + resultBuilderEntity.addProperty( fetchable, columnAliases ); } } @@ -566,10 +573,10 @@ private void processFetchReturn(NativeQuery.FetchReturn fetchReturn) { } EntityPersister ownerPersister = alias2Persister.get( ownerAlias ); - Type returnType = ownerPersister.getPropertyType( fetchReturn.getFetchableName() ); + Type returnType = ownerPersister.getPropertyType( fetchReturn.getFetchable().getFetchableName() ); if ( returnType instanceof CollectionType ) { - String role = ownerPersister.getEntityName() + '.' + fetchReturn.getFetchableName(); + String role = ownerPersister.getEntityName() + '.' + fetchReturn.getFetchable().getFetchableName(); Map propertyResultsMap = Collections.emptyMap();//fetchReturn.getPropertyResultsMap() addCollection( role, alias, propertyResultsMap ); // collectionOwnerAliases.add( ownerAlias ); diff --git a/hibernate-core/src/main/java/org/hibernate/sql/ast/spi/SqlExpressionResolver.java b/hibernate-core/src/main/java/org/hibernate/sql/ast/spi/SqlExpressionResolver.java index b52df9099747..956fa98b6622 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/ast/spi/SqlExpressionResolver.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/ast/spi/SqlExpressionResolver.java @@ -6,6 +6,7 @@ import java.util.function.Function; +import org.hibernate.metamodel.mapping.EntityDiscriminatorMapping; import org.hibernate.metamodel.mapping.JdbcMapping; import org.hibernate.metamodel.mapping.SelectableMapping; import org.hibernate.metamodel.mapping.SelectablePath; @@ -90,6 +91,15 @@ static ColumnReferenceKey createColumnReferenceKey(TableReference tableReference return createColumnReferenceKey( tableReference, selectable.getSelectablePath(), selectable.getJdbcMapping() ); } + /** + * Convenience form for creating a key from TableReference and EntityDiscriminatorMapping + */ + static ColumnReferenceKey createDiscriminatorColumnReferenceKey(TableReference tableReference, EntityDiscriminatorMapping discriminatorMapping) { + assert tableReference.containsAffectedTableName( discriminatorMapping.getContainingTableExpression() ) + : String.format( ROOT, "Expecting tables to match between TableReference (%s) and SelectableMapping (%s)", tableReference.getTableId(), discriminatorMapping.getContainingTableExpression() ); + return createColumnReferenceKey( tableReference, discriminatorMapping.getSelectablePath(), discriminatorMapping.getUnderlyingJdbcMapping() ); + } + default Expression resolveSqlExpression(TableReference tableReference, SelectableMapping selectableMapping) { return resolveSqlExpression( createColumnReferenceKey( tableReference, selectableMapping ), diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/inheritance/SingleTableNativeQueryTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/inheritance/SingleTableNativeQueryTest.java new file mode 100644 index 000000000000..cc1f292fcb69 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/inheritance/SingleTableNativeQueryTest.java @@ -0,0 +1,456 @@ +/* + * SPDX-License-Identifier: LGPL-2.1-or-later + * Copyright Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.orm.test.inheritance; + +import jakarta.persistence.CascadeType; +import jakarta.persistence.Column; +import jakarta.persistence.DiscriminatorColumn; +import jakarta.persistence.DiscriminatorType; +import jakarta.persistence.DiscriminatorValue; +import jakarta.persistence.Embeddable; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.Inheritance; +import jakarta.persistence.InheritanceType; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.OneToMany; +import jakarta.persistence.OneToOne; +import jakarta.persistence.Table; +import org.hibernate.testing.orm.junit.DomainModel; +import org.hibernate.testing.orm.junit.JiraKey; +import org.hibernate.testing.orm.junit.SessionFactory; +import org.hibernate.testing.orm.junit.SessionFactoryScope; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.contains; +import static org.hamcrest.Matchers.instanceOf; +import static org.hamcrest.core.Is.is; + +@JiraKey("HHH-18610") +@DomainModel( + annotatedClasses = { + SingleTableNativeQueryTest.Toy.class, + SingleTableNativeQueryTest.Color.class, + SingleTableNativeQueryTest.Family.class, + SingleTableNativeQueryTest.Person.class, + SingleTableNativeQueryTest.Child.class, + SingleTableNativeQueryTest.Man.class, + SingleTableNativeQueryTest.Woman.class + } +) +@SessionFactory +public class SingleTableNativeQueryTest { + + @BeforeEach + public void setUp(SessionFactoryScope scope) { + scope.inTransaction( + session -> { + Toy marioToy; + Toy fidgetSpinner; + Man john; + Woman jane; + Child susan; + Child mark; + Family family; + List children; + List familyMembers; + + marioToy = new Toy( 1L, "Super Mario retro Mushroom" ); + fidgetSpinner = new Toy( 2L, "Fidget Spinner" ); + john = new Man( "John", "Riding Roller Coasters" ); + jane = new Woman( "Jane", "Hippotherapist" ); + susan = new Child( "Susan", marioToy ); + mark = new Child( "Mark", fidgetSpinner ); + family = new Family( "McCloud" ); + children = new ArrayList<>( Arrays.asList( susan, mark ) ); + familyMembers = Arrays.asList( john, jane, susan, mark ); + + + session.persist( marioToy ); + session.persist( fidgetSpinner ); + + jane.setColor( new Color( "pink" ) ); + jane.setHusband( john ); + jane.setChildren( children ); + + john.setColor( new Color( "blue" ) ); + john.setWife( jane ); + john.setChildren( children ); + + for ( Child child : children ) { + child.setFather( john ); + child.setMother( jane ); + } + + for ( Person person : familyMembers ) { + family.add( person ); + } + + session.persist( family ); + } ); + } + + @AfterEach + public void tearDown(SessionFactoryScope scope) { + scope.getSessionFactory().getSchemaManager().truncateMappedObjects(); + } + + @Test + public void itShouldGetPersons(SessionFactoryScope scope) { + scope.inTransaction( + session -> { + List results = session.createNativeQuery( "select {p.*} from person p order by p.name", + Object.class ).addEntity( "p", Person.class ).list(); + assertThat( results.stream().map( p -> ((Person) p).getName() ).collect( Collectors.toList() ), + contains( "Jane", "John", "Mark", "Susan" ) ); + } + ); + } + + @Test + public void itShouldGetWife(SessionFactoryScope scope) { + scope.inTransaction( + session -> { + List results = session.createNativeQuery( + "select {m.*}, {w.*} from person m left join person w on m.wife_name = w.name where m.TYPE = 'MAN'", + Object[].class ) + .addEntity( "m", Person.class ) + .addEntity( "w", Person.class ) + .list(); + assertThat( results.size(), is( 1 ) ); + assertThat( results.get( 0 )[0], instanceOf( Man.class ) ); + assertThat( ((Man) results.get( 0 )[0]).getName(), is( "John" ) ); + assertThat( results.get( 0 )[1], instanceOf( Woman.class ) ); + assertThat( ((Woman) results.get( 0 )[1]).getName(), is( "Jane" ) ); + } + ); + } + + @Test + public void itShouldGetFamilyMembers(SessionFactoryScope scope) { + scope.inTransaction( + session -> { + List results = session.createNativeQuery( "select {f.*} from family f", Object.class ) + .addEntity( "f", Family.class ).list(); + Family family = (Family) results.get( 0 ); + List members = family.getMembers(); + assertThat( members.size(), is( 4 ) ); + } + ); + } + + @Embeddable + public static class Color { + @Column(name = "color") + private String attributes; + + public Color() { + } + + public Color(final String attributes) { + this.attributes = attributes; + } + + public String getAttributes() { + return attributes; + } + + public void setAttributes(final String attributes) { + this.attributes = attributes; + } + } + + @Entity(name = "Family") + @Table(name = "family") + public static class Family { + + @Id + private String name; + + @OneToMany(mappedBy = "familyName", cascade = CascadeType.ALL, orphanRemoval = true) + private List members = new ArrayList<>(); + + public Family() { + } + + public Family(String name) { + this.name = name; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public List getMembers() { + return members; + } + + public void setMembers(List members) { + this.members = members; + } + + public void add(Person person) { + person.setFamilyName( this ); + members.add( person ); + } + + @Override + public String toString() { + return "Family [name=" + name + "]"; + } + } + + @Entity(name = "Person") + @Table(name = "person") + @Inheritance(strategy = InheritanceType.SINGLE_TABLE) + @DiscriminatorColumn(name = "TYPE", discriminatorType = DiscriminatorType.STRING) + public static class Person { + + @Id + private String name; + + @ManyToOne + private Family familyName; + + public Person() { + } + + public Person(String name) { + this.name = name; + } + + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Family getFamilyName() { + return familyName; + } + + public void setFamilyName(Family familyName) { + this.familyName = familyName; + } + + @Override + public String toString() { + return name; + } + } + + + @Entity(name = "Toy") + @Table(name = "toy") + public static class Toy { + + @Id + private Long id; + + private String name; + + @OneToMany(mappedBy = "favoriteThing", cascade = CascadeType.ALL, orphanRemoval = true) + List favorite = new ArrayList<>(); + + public Toy() { + } + + public Toy(final Long id, final String name) { + this.id = id; + this.name = name; + } + + public Long getId() { + return id; + } + + public void setId(final Long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(final String name) { + this.name = name; + } + } + + @Entity(name = "Child") + @DiscriminatorValue("CHILD") + public static class Child extends Person { + + @ManyToOne + @JoinColumn(name = "fav_toy") + private Toy favoriteThing; + + @ManyToOne + private Woman mother; + + @ManyToOne + private Man father; + + public Child() { + } + + public Child(String name, Toy favouriteThing) { + super( name ); + this.favoriteThing = favouriteThing; + } + + public Toy getFavoriteThing() { + return favoriteThing; + } + + public void setFavoriteThing(Toy favouriteThing) { + this.favoriteThing = favouriteThing; + } + + public Man getFather() { + return father; + } + + public void setFather(Man father) { + this.father = father; + } + + public Woman getMother() { + return mother; + } + + public void setMother(Woman mother) { + this.mother = mother; + } + } + + @Entity(name = "Man") + @DiscriminatorValue("MAN") + public static class Man extends Person { + + private Color color; + + @Column(name = "fav_hobby") + private String favoriteThing; + + @OneToOne + private Woman wife; + + @OneToMany(mappedBy = "father") + private List children = new ArrayList<>(); + + public Man() { + } + + public Man(String name, String favoriteThing) { + super( name ); + this.favoriteThing = favoriteThing; + } + + public String getFavoriteThing() { + return favoriteThing; + } + + public void setFavoriteThing(String favoriteThing) { + this.favoriteThing = favoriteThing; + } + + public Woman getWife() { + return wife; + } + + public void setWife(Woman wife) { + this.wife = wife; + } + + public List getChildren() { + return children; + } + + public void setChildren(List children) { + this.children = children; + } + + public Color getColor() { + return color; + } + + public void setColor(final Color color) { + this.color = color; + } + } + + @Entity(name = "Woman") + @DiscriminatorValue("WOMAN") + public static class Woman extends Person { + + private Color color; + + private String job; + + @OneToOne + private Man husband; + + @OneToMany(mappedBy = "mother") + private List children = new ArrayList<>(); + + public Woman() { + } + + public Woman(String name, String job) { + super( name ); + this.job = job; + } + + + public String getJob() { + return job; + } + + public void setJob(String job) { + this.job = job; + } + + public Man getHusband() { + return husband; + } + + public void setHusband(Man husband) { + this.husband = husband; + } + + public List getChildren() { + return children; + } + + public void setChildren(List children) { + this.children = children; + } + + public Color getColor() { + return color; + } + + public void setColor(final Color color) { + this.color = color; + } + } +}