HHH-18610 SQLGrammarException: Unable to find column position by name: TYPE when using Single Table Inheritance with a strict JDBC driver such as PostgreSQL

This commit is contained in:
Andrea Boriero 2024-10-01 09:53:15 +02:00 committed by Andrea Boriero
parent cd47e91900
commit 49886d1fd5
25 changed files with 551 additions and 419 deletions

View File

@ -13,6 +13,7 @@ import org.hibernate.event.spi.MergeContext;
import jakarta.persistence.EmbeddedId;
import jakarta.persistence.Id;
import jakarta.persistence.IdClass;
import org.hibernate.sql.results.graph.Fetchable;
/**
@ -22,7 +23,7 @@ import jakarta.persistence.IdClass;
* @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";

View File

@ -21,6 +21,7 @@ import org.hibernate.metamodel.mapping.EntityMappingType;
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;
@ -504,6 +505,8 @@ public interface NativeQuery<T> extends Query<T>, SynchronizeableQuery {
String getOwnerAlias();
Fetchable getFetchable();
String getFetchableName();
/**

View File

@ -30,6 +30,7 @@ import org.hibernate.sql.results.graph.FetchableContainer;
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 class FetchMementoHbmStandard implements FetchMemento, FetchMemento.Paren
Parent parent,
Consumer<String> querySpaceConsumer,
ResultSetMappingResolutionContext context) {
final Map<String, FetchBuilder> 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<String, FetchBuilder> 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<String> querySpaceConsumer,
ResultSetMappingResolutionContext context) {
final DynamicResultBuilderEntityStandard resultBuilder;
EntityMappingType partMappingType = (EntityMappingType) pluralAttributeMapping.getElementDescriptor()
.getPartMappingType();
resultBuilder = new DynamicResultBuilderEntityStandard(
partMappingType,
tableAlias,
navigablePath
);
final Map<Fetchable, FetchBuilder> 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.getFetchableName(),
fetchable,
keyColumnNames,
fetchBuilderMap,
resultBuilder
);
}
private FetchBuilder resolve(
ToOneAttributeMapping toOneAttributeMapping,
Consumer<String> querySpaceConsumer,
ResultSetMappingResolutionContext context) {
final Map<Fetchable, FetchBuilder> 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,
keyColumnNames,
fetchBuilderMap,
resultBuilder

View File

@ -23,6 +23,7 @@ import org.hibernate.query.results.internal.complete.CompleteResultBuilderEntity
import org.hibernate.query.results.internal.complete.DelayedFetchBuilderBasicPart;
import org.hibernate.query.results.internal.implicit.ImplicitFetchBuilderBasic;
import org.hibernate.spi.NavigablePath;
import org.hibernate.sql.results.graph.Fetchable;
/**
* @author Steve Ebersole
@ -70,13 +71,13 @@ public class ResultMementoEntityJpa implements ResultMementoEntity, FetchMemento
}
}
final HashMap<String, FetchBuilder> explicitFetchBuilderMap = new HashMap<>();
final HashMap<Fetchable, FetchBuilder> 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 class ResultMementoEntityJpa implements ResultMementoEntity, FetchMemento
attributeMapping -> {
final BasicValuedModelPart basicPart = attributeMapping.asBasicValuedModelPart();
if ( basicPart != null ) {
final Function<String, FetchBuilder> fetchBuilderCreator = k -> new DelayedFetchBuilderBasicPart(
navigablePath.append( k ),
final Function<Fetchable, FetchBuilder> fetchBuilderCreator = k -> new DelayedFetchBuilderBasicPart(
navigablePath.append( k.getFetchableName() ),
basicPart,
isEnhancedForLazyLoading
);
explicitFetchBuilderMap.computeIfAbsent(
attributeMapping.getFetchableName(),
attributeMapping,
fetchBuilderCreator
);
}

View File

@ -10,15 +10,16 @@ import java.util.function.Consumer;
import org.hibernate.LockMode;
import org.hibernate.metamodel.mapping.EntityMappingType;
import org.hibernate.query.results.FetchBuilderBasicValued;
import org.hibernate.spi.NavigablePath;
import org.hibernate.query.QueryLogging;
import org.hibernate.query.named.FetchMemento;
import org.hibernate.query.named.FetchMementoBasic;
import org.hibernate.query.named.ResultMementoEntity;
import org.hibernate.query.results.FetchBuilderBasicValued;
import org.hibernate.query.results.FetchBuilder;
import org.hibernate.query.results.ResultBuilderEntityValued;
import org.hibernate.query.results.internal.complete.CompleteResultBuilderEntityStandard;
import org.hibernate.sql.results.graph.Fetchable;
/**
* @author Steve Ebersole
@ -64,11 +65,11 @@ public class ResultMementoEntityStandard implements ResultMementoEntity, FetchMe
? (FetchBuilderBasicValued) discriminatorMemento.resolve( this, querySpaceConsumer, context )
: null;
final HashMap<String, FetchBuilder> fetchBuilderMap = new HashMap<>();
final HashMap<Fetchable, FetchBuilder> fetchBuilderMap = new HashMap<>();
fetchMementoMap.forEach(
(attrName, fetchMemento) -> fetchBuilderMap.put(
attrName,
(Fetchable) entityDescriptor.findByPath( attrName ),
fetchMemento.resolve(this, querySpaceConsumer, context )
)
);

View File

@ -9,6 +9,7 @@ import org.hibernate.spi.NavigablePath;
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 java.util.function.BiConsumer;
@ -33,7 +34,7 @@ public interface FetchBuilder extends GraphNodeBuilder {
JdbcValuesMetadata jdbcResultsMetadata,
DomainResultCreationState domainResultCreationState);
default void visitFetchBuilders(BiConsumer<String, FetchBuilder> consumer) {
default void visitFetchBuilders(BiConsumer<Fetchable, FetchBuilder> consumer) {
}
FetchBuilder cacheKeyInstance();

View File

@ -4,6 +4,8 @@
*/
package org.hibernate.query.results;
import org.hibernate.sql.results.graph.Fetchable;
/**
* Specialized FetchBuilder implementations which handle building fetches defined via:<ul>
* <li>{@code hbm.xml} definitions</li>
@ -30,4 +32,6 @@ public interface LegacyFetchBuilder extends FetchBuilder {
@Override
LegacyFetchBuilder cacheKeyInstance();
Fetchable getFetchable();
}

View File

@ -7,6 +7,7 @@ package org.hibernate.query.results;
import org.hibernate.Incubating;
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 java.util.function.BiConsumer;
@ -46,6 +47,6 @@ public interface ResultBuilder extends GraphNodeBuilder {
ResultBuilder cacheKeyInstance();
default void visitFetchBuilders(BiConsumer<String, FetchBuilder> consumer) {
default void visitFetchBuilders(BiConsumer<Fetchable, FetchBuilder> consumer) {
}
}

View File

@ -240,8 +240,8 @@ public class Builders {
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(

View File

@ -12,14 +12,10 @@ import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.internal.util.collections.Stack;
import org.hibernate.internal.util.collections.StandardStack;
import org.hibernate.metamodel.mapping.Association;
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.query.results.FetchBuilder;
import org.hibernate.query.results.LegacyFetchBuilder;
@ -47,7 +43,6 @@ import org.hibernate.sql.results.jdbc.spi.JdbcValuesMetadata;
import org.hibernate.type.descriptor.java.JavaType;
import org.hibernate.type.spi.TypeConfiguration;
import java.util.AbstractMap;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Consumer;
@ -83,7 +78,6 @@ public class DomainResultCreationStateImpl
private final SessionFactoryImplementor sessionFactory;
private final Stack<Function> fetchBuilderResolverStack = new StandardStack<>( Function.class, fetchableName -> null );
private final Stack<Map.Entry> relativePathStack = new StandardStack<>( Map.Entry.class );
private Map<String, LockMode> registeredLockModes;
private boolean processingKeyFetches = false;
private boolean resolvingCircularFetch;
@ -92,7 +86,7 @@ public class DomainResultCreationStateImpl
public DomainResultCreationStateImpl(
String stateIdentifier,
JdbcValuesMetadata jdbcResultsMetadata,
Map<String, Map<String, LegacyFetchBuilder>> legacyFetchBuilders,
Map<String, Map<Fetchable, LegacyFetchBuilder>> legacyFetchBuilders,
Consumer<SqlSelection> sqlSelectionConsumer,
LoadQueryInfluencers loadQueryInfluencers,
SessionFactoryImplementor sessionFactory) {
@ -129,33 +123,26 @@ public class DomainResultCreationStateImpl
return jdbcResultsMetadata;
}
public Map.Entry<String, NavigablePath> getCurrentRelativePath() {
//noinspection unchecked
return relativePathStack.getCurrent();
}
public void pushExplicitFetchMementoResolver(Function<String, FetchBuilder> resolver) {
public void pushExplicitFetchMementoResolver(Function<Fetchable, FetchBuilder> resolver) {
fetchBuilderResolverStack.push( resolver );
}
public Function<String, FetchBuilder> getCurrentExplicitFetchMementoResolver() {
//noinspection unchecked
public Function<Fetchable, FetchBuilder> getCurrentExplicitFetchMementoResolver() {
return fetchBuilderResolverStack.getCurrent();
}
public Function<String, FetchBuilder> popExplicitFetchMementoResolver() {
//noinspection unchecked
public Function<Fetchable, FetchBuilder> popExplicitFetchMementoResolver() {
return fetchBuilderResolverStack.pop();
}
@SuppressWarnings( "unused" )
public void withExplicitFetchMementoResolver(Function<String, FetchBuilder> resolver, Runnable runnable) {
public void withExplicitFetchMementoResolver(Function<Fetchable, FetchBuilder> resolver, Runnable runnable) {
pushExplicitFetchMementoResolver( resolver );
try {
runnable.run();
}
finally {
final Function<String, FetchBuilder> popped = popExplicitFetchMementoResolver();
final Function<Fetchable, FetchBuilder> popped = popExplicitFetchMementoResolver();
assert popped == resolver;
}
}
@ -270,7 +257,7 @@ public class DomainResultCreationStateImpl
sqlSelectionMap.put( key, (ResultSetMappingSqlSelection) created );
sqlSelectionConsumer.accept( (ResultSetMappingSqlSelection) created );
}
else if ( created instanceof ColumnReference columnReference ) {
else if ( created instanceof ColumnReference columnReference) {
final String selectableName = columnReference.getSelectableName();
final int valuesArrayPosition;
if ( nestingFetchParent != null ) {
@ -328,23 +315,23 @@ public class DomainResultCreationStateImpl
}
private static class LegacyFetchResolver {
private final Map<String,Map<String, LegacyFetchBuilder>> legacyFetchBuilders;
private final Map<String,Map<Fetchable, LegacyFetchBuilder>> legacyFetchBuilders;
public LegacyFetchResolver(Map<String, Map<String, LegacyFetchBuilder>> legacyFetchBuilders) {
public LegacyFetchResolver(Map<String, Map<Fetchable, LegacyFetchBuilder>> legacyFetchBuilders) {
this.legacyFetchBuilders = legacyFetchBuilders;
}
public LegacyFetchBuilder resolve(String ownerTableAlias, String fetchedPartPath) {
public LegacyFetchBuilder resolve(String ownerTableAlias, Fetchable fetchedPart) {
if ( legacyFetchBuilders == null ) {
return null;
}
final Map<String, LegacyFetchBuilder> fetchBuilders = legacyFetchBuilders.get( ownerTableAlias );
final Map<Fetchable, LegacyFetchBuilder> fetchBuilders = legacyFetchBuilders.get( ownerTableAlias );
if ( fetchBuilders == null ) {
return null;
}
return fetchBuilders.get( fetchedPartPath );
return fetchBuilders.get( fetchedPart );
}
}
@ -362,28 +349,18 @@ public class DomainResultCreationStateImpl
final EntityValuedModelPart parentModelPart = fetchParent.getEntityValuedModelPart();
final EntityIdentifierMapping identifierMapping = parentModelPart.getEntityMappingType().getIdentifierMapping();
final String identifierAttributeName = attributeName( identifierMapping );
//noinspection unchecked
final Map.Entry<String, NavigablePath> 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;
//noinspection unchecked
final FetchBuilder explicitFetchBuilder = (FetchBuilder) fetchBuilderResolverStack.getCurrent().apply( fullPath );
final FetchBuilder explicitFetchBuilder = (FetchBuilder) fetchBuilderResolverStack
.getCurrent()
.apply( identifierMapping );
LegacyFetchBuilder fetchBuilderLegacy;
if ( explicitFetchBuilder == null ) {
fetchBuilderLegacy = legacyFetchResolver.resolve(
fromClauseAccess.findTableGroup( fetchParent.getNavigablePath() )
.getPrimaryTableReference()
.getIdentificationVariable(),
identifierAttributeName
identifierMapping
);
}
else {
@ -397,9 +374,6 @@ public class DomainResultCreationStateImpl
final boolean processingKeyFetches = this.processingKeyFetches;
this.processingKeyFetches = true;
if ( identifierMapping instanceof CompositeIdentifierMapping ) {
relativePathStack.push( new AbstractMap.SimpleEntry<>( fullPath, fetchPath ) );
}
try {
final FetchBuilder fetchBuilder;
@ -410,7 +384,7 @@ public class DomainResultCreationStateImpl
fetchBuilder = fetchBuilderLegacy;
}
else {
fetchBuilder = Builders.implicitFetchBuilder( fetchPath, identifierFetchable, this );
fetchBuilder = Builders.implicitFetchBuilder( fetchPath, identifierMapping, this );
}
return fetchBuilder.buildFetch(
@ -422,9 +396,6 @@ public class DomainResultCreationStateImpl
}
finally {
this.processingKeyFetches = processingKeyFetches;
if ( identifierMapping instanceof CompositeIdentifierMapping ) {
this.relativePathStack.pop();
}
}
}
@ -443,34 +414,16 @@ public class DomainResultCreationStateImpl
if ( !fetchable.isSelectable() ) {
return;
}
final String fetchableName = fetchable.getFetchableName();
Map.Entry<String, NavigablePath> currentEntry;
if ( relativePathStack.isEmpty() ) {
currentEntry = new AbstractMap.SimpleEntry<>(
getRelativePath( "", fetchable ),
new NavigablePath( fetchableName )
);
}
else {
//noinspection unchecked
final Map.Entry<String, NavigablePath> 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();
//noinspection unchecked
FetchBuilder explicitFetchBuilder = (FetchBuilder) fetchBuilderResolverStack.getCurrent().apply( fullPath );
FetchBuilder explicitFetchBuilder = (FetchBuilder) fetchBuilderResolverStack
.getCurrent()
.apply( fetchable );
LegacyFetchBuilder fetchBuilderLegacy;
if ( explicitFetchBuilder == null ) {
fetchBuilderLegacy = legacyFetchResolver.resolve(
fromClauseAccess.findTableGroup( fetchParent.getNavigablePath() )
.getPrimaryTableReference()
.getIdentificationVariable(),
fetchableName
fetchable
);
}
else {
@ -478,67 +431,44 @@ public class DomainResultCreationStateImpl
}
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 )
);
//noinspection unchecked
explicitFetchBuilder = (FetchBuilder) fetchBuilderResolverStack.getCurrent().apply( currentEntry.getKey() );
if ( explicitFetchBuilder == null && fetchBuilderLegacy == null ) {
explicitFetchBuilder = (FetchBuilder) fetchBuilderResolverStack
.getCurrent()
.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;
}
else if ( fetchBuilderLegacy == null ) {
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 {
fetchBuilder = fetchBuilderLegacy;
}
final Fetch fetch = fetchBuilder.buildFetch(
fetchParent,
fetchPath,
jdbcResultsMetadata,
this
);
fetches.add( fetch );
}
finally {
relativePathStack.pop();
}
final Fetch fetch = fetchBuilder.buildFetch(
fetchParent,
fetchPath,
jdbcResultsMetadata,
this
);
fetches.add( fetch );
};
}
private String getRelativePath(String oldEntry, Fetchable fetchable) {
if ( fetchable instanceof AttributeMapping || fetchable instanceof BasicValuedCollectionPart ) {
if ( !"".equals( oldEntry ) ) {
return oldEntry + '.' + fetchable.getFetchableName();
}
return fetchable.getFetchableName();
}
return oldEntry;
}
@Override
public boolean isResolvingCircularFetch() {
return resolvingCircularFetch;

View File

@ -16,6 +16,7 @@ import org.hibernate.query.results.ResultBuilder;
import org.hibernate.query.results.ResultSetMapping;
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;
@ -44,7 +45,7 @@ public class ResultSetMappingImpl implements ResultSetMapping {
private final String mappingIdentifier;
private final boolean isDynamic;
private List<ResultBuilder> resultBuilders;
private Map<String, Map<String, LegacyFetchBuilder>> legacyFetchBuilders;
private Map<String, Map<Fetchable, LegacyFetchBuilder>> legacyFetchBuilders;
public ResultSetMappingImpl(String mappingIdentifier) {
this( mappingIdentifier, false );
@ -72,15 +73,15 @@ public class ResultSetMappingImpl implements ResultSetMapping {
this.legacyFetchBuilders = null;
}
else {
final Map<String, Map<String, LegacyFetchBuilder>> legacyFetchBuilders = new HashMap<>( original.legacyFetchBuilders.size() );
for ( Map.Entry<String, Map<String, LegacyFetchBuilder>> entry : original.legacyFetchBuilders.entrySet() ) {
final Map<String, LegacyFetchBuilder> newValue = new HashMap<>( entry.getValue().size() );
for ( Map.Entry<String, LegacyFetchBuilder> builderEntry : entry.getValue().entrySet() ) {
final Map<String, Map<Fetchable, LegacyFetchBuilder>> builders = new HashMap<>( original.legacyFetchBuilders.size() );
for ( Map.Entry<String, Map<Fetchable, LegacyFetchBuilder>> entry : original.legacyFetchBuilders.entrySet() ) {
final Map<Fetchable, LegacyFetchBuilder> newValue = new HashMap<>( entry.getValue().size() );
for ( Map.Entry<Fetchable, LegacyFetchBuilder> 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;
}
}
@ -123,7 +124,7 @@ public class ResultSetMappingImpl implements ResultSetMapping {
return;
}
for ( Map.Entry<String, Map<String, LegacyFetchBuilder>> entry : legacyFetchBuilders.entrySet() ) {
for ( Map.Entry<String, Map<Fetchable, LegacyFetchBuilder>> entry : legacyFetchBuilders.entrySet() ) {
for ( LegacyFetchBuilder fetchBuilder : entry.getValue().values() ) {
resultBuilderConsumer.accept( fetchBuilder );
}
@ -140,7 +141,7 @@ public class ResultSetMappingImpl implements ResultSetMapping {
@Override
public void addLegacyFetchBuilder(LegacyFetchBuilder fetchBuilder) {
final Map<String, LegacyFetchBuilder> existingFetchBuildersByOwner;
final Map<Fetchable, LegacyFetchBuilder> existingFetchBuildersByOwner;
if ( legacyFetchBuilders == null ) {
legacyFetchBuilders = new HashMap<>();
@ -150,7 +151,7 @@ public class ResultSetMappingImpl implements ResultSetMapping {
existingFetchBuildersByOwner = legacyFetchBuilders.get( fetchBuilder.getOwnerAlias() );
}
final Map<String, LegacyFetchBuilder> fetchBuildersByOwner;
final Map<Fetchable, LegacyFetchBuilder> fetchBuildersByOwner;
if ( existingFetchBuildersByOwner == null ) {
fetchBuildersByOwner = new HashMap<>();
legacyFetchBuilders.put( fetchBuilder.getOwnerAlias(), fetchBuildersByOwner );
@ -159,7 +160,7 @@ public class ResultSetMappingImpl implements ResultSetMapping {
fetchBuildersByOwner = existingFetchBuildersByOwner;
}
fetchBuildersByOwner.put( fetchBuilder.getFetchableName(), fetchBuilder );
fetchBuildersByOwner.put( fetchBuilder.getFetchable(), fetchBuilder );
}
@Override

View File

@ -4,6 +4,7 @@
*/
package org.hibernate.query.results.internal;
import org.hibernate.metamodel.mapping.EntityDiscriminatorMapping;
import org.hibernate.metamodel.mapping.ModelPart;
import org.hibernate.metamodel.mapping.SelectableMapping;
import org.hibernate.metamodel.mapping.internal.SingleAttributeIdentifierMapping;
@ -13,6 +14,7 @@ import org.hibernate.sql.results.graph.DomainResultCreationState;
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
@ -60,6 +62,25 @@ public class ResultsHelper {
);
}
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,

View File

@ -15,6 +15,7 @@ import org.hibernate.query.results.internal.ResultsHelper;
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;
@ -37,14 +38,14 @@ public class CompleteResultBuilderEntityJpa implements CompleteResultBuilderEnti
private final EntityMappingType entityDescriptor;
private final LockMode lockMode;
private final FetchBuilderBasicValued discriminatorFetchBuilder;
private final HashMap<String, FetchBuilder> explicitFetchBuilderMap;
private final HashMap<Fetchable, FetchBuilder> explicitFetchBuilderMap;
public CompleteResultBuilderEntityJpa(
NavigablePath navigablePath,
EntityMappingType entityDescriptor,
LockMode lockMode,
FetchBuilderBasicValued discriminatorFetchBuilder,
HashMap<String, FetchBuilder> explicitFetchBuilderMap) {
HashMap<Fetchable, FetchBuilder> explicitFetchBuilderMap) {
this.navigablePath = navigablePath;
this.entityDescriptor = entityDescriptor;
this.lockMode = lockMode;
@ -132,7 +133,7 @@ public class CompleteResultBuilderEntityJpa implements CompleteResultBuilderEnti
}
@Override
public void visitFetchBuilders(BiConsumer<String, FetchBuilder> consumer) {
public void visitFetchBuilders(BiConsumer<Fetchable, FetchBuilder> consumer) {
explicitFetchBuilderMap.forEach( consumer );
}

View File

@ -16,6 +16,7 @@ import org.hibernate.query.results.internal.ResultsHelper;
import org.hibernate.spi.NavigablePath;
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;
@ -32,7 +33,7 @@ public class CompleteResultBuilderEntityStandard implements CompleteResultBuilde
private final EntityMappingType entityDescriptor;
private final LockMode lockMode;
private final FetchBuilderBasicValued discriminatorFetchBuilder;
private final HashMap<String, FetchBuilder> explicitFetchBuilderMap;
private final HashMap<Fetchable, FetchBuilder> explicitFetchBuilderMap;
public CompleteResultBuilderEntityStandard(
String tableAlias,
@ -40,7 +41,7 @@ public class CompleteResultBuilderEntityStandard implements CompleteResultBuilde
EntityMappingType entityDescriptor,
LockMode lockMode,
FetchBuilderBasicValued discriminatorFetchBuilder,
HashMap<String, FetchBuilder> explicitFetchBuilderMap) {
HashMap<Fetchable, FetchBuilder> explicitFetchBuilderMap) {
this.tableAlias = tableAlias;
this.navigablePath = navigablePath;
this.entityDescriptor = entityDescriptor;
@ -161,7 +162,7 @@ public class CompleteResultBuilderEntityStandard implements CompleteResultBuilde
}
@Override
public void visitFetchBuilders(BiConsumer<String, FetchBuilder> consumer) {
public void visitFetchBuilders(BiConsumer<Fetchable, FetchBuilder> consumer) {
explicitFetchBuilderMap.forEach( consumer );
}

View File

@ -11,13 +11,14 @@ import java.util.Objects;
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<T extends AbstractFetchBuilderContainer<T>>
implements DynamicFetchBuilderContainer {
private Map<String, FetchBuilder> fetchBuilderMap;
private Map<Fetchable, FetchBuilder> fetchBuilderMap;
protected AbstractFetchBuilderContainer() {
}
@ -25,7 +26,7 @@ public abstract class AbstractFetchBuilderContainer<T extends AbstractFetchBuild
protected AbstractFetchBuilderContainer(AbstractFetchBuilderContainer<T> original) {
if ( original.fetchBuilderMap != null ) {
fetchBuilderMap = new HashMap<>( original.fetchBuilderMap.size() );
for ( Map.Entry<String, FetchBuilder> entry : original.fetchBuilderMap.entrySet() ) {
for ( Map.Entry<Fetchable, FetchBuilder> entry : original.fetchBuilderMap.entrySet() ) {
final FetchBuilder fetchBuilder =
entry.getValue() instanceof DynamicFetchBuilderStandard dynamicFetchBuilderStandard
? dynamicFetchBuilderStandard.cacheKeyInstance( this )
@ -38,54 +39,55 @@ public abstract class AbstractFetchBuilderContainer<T extends AbstractFetchBuild
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
)
);
}
}
final DynamicFetchBuilderStandard fetchBuilder = new DynamicFetchBuilderStandard( propertyName );
fetchBuilderMap.put( propertyName, fetchBuilder );
final DynamicFetchBuilderStandard fetchBuilder = new DynamicFetchBuilderStandard( fetchable );
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

View File

@ -5,6 +5,7 @@
package org.hibernate.query.results.internal.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);
}

View File

@ -7,11 +7,14 @@ package org.hibernate.query.results.internal.dynamic;
import org.hibernate.AssertionFailure;
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.FetchBuilder;
@ -28,6 +31,7 @@ import org.hibernate.sql.ast.tree.from.TableReference;
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 java.util.HashMap;
@ -46,16 +50,16 @@ public class DynamicFetchBuilderLegacy
implements LegacyFetchBuilder, DynamicFetchBuilder,
NativeQuery.FetchReturn, NativeQuery.ReturnableResultNode, 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<String> columnNames;
private final Map<String, FetchBuilder> fetchBuilderMap;
private final Map<Fetchable, FetchBuilder> fetchBuilderMap;
private final DynamicResultBuilderEntityStandard resultBuilderEntity;
private LockMode lockMode;
@ -63,22 +67,22 @@ public class DynamicFetchBuilderLegacy
public DynamicFetchBuilderLegacy(
String tableAlias,
String ownerTableAlias,
String fetchableName,
Fetchable fetchable,
List<String> columnNames,
Map<String, FetchBuilder> fetchBuilderMap) {
this( tableAlias, ownerTableAlias, fetchableName, columnNames, fetchBuilderMap, null );
Map<Fetchable, FetchBuilder> fetchBuilderMap) {
this( tableAlias, ownerTableAlias, fetchable, columnNames, fetchBuilderMap, null );
}
public DynamicFetchBuilderLegacy(
String tableAlias,
String ownerTableAlias,
String fetchableName,
Fetchable fetchable,
List<String> columnNames,
Map<String, FetchBuilder> fetchBuilderMap,
Map<Fetchable, FetchBuilder> fetchBuilderMap,
DynamicResultBuilderEntityStandard resultBuilderEntity) {
this.tableAlias = tableAlias;
this.ownerTableAlias = ownerTableAlias;
this.fetchableName = fetchableName;
this.fetchable = fetchable;
this.columnNames = columnNames;
this.fetchBuilderMap = fetchBuilderMap;
this.resultBuilderEntity = resultBuilderEntity;
@ -94,9 +98,55 @@ public class DynamicFetchBuilderLegacy
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
@ -104,20 +154,20 @@ public class DynamicFetchBuilderLegacy
return new DynamicFetchBuilderLegacy(
tableAlias,
ownerTableAlias,
fetchableName,
fetchable,
columnNames == null ? null : List.copyOf( columnNames ),
fetchBuilderMap(),
resultBuilderEntity == null ? null : resultBuilderEntity.cacheKeyInstance()
);
}
private Map<String, FetchBuilder> fetchBuilderMap() {
private Map<Fetchable, FetchBuilder> fetchBuilderMap() {
if ( this.fetchBuilderMap == null ) {
return null;
}
else {
final Map<String, FetchBuilder> fetchBuilderMap = new HashMap<>( this.fetchBuilderMap.size() );
for ( Map.Entry<String, FetchBuilder> entry : this.fetchBuilderMap.entrySet() ) {
final Map<Fetchable, FetchBuilder> fetchBuilderMap = new HashMap<>( this.fetchBuilderMap.size() );
for ( Map.Entry<Fetchable, FetchBuilder> entry : this.fetchBuilderMap.entrySet() ) {
fetchBuilderMap.put( entry.getKey(), entry.getValue().cacheKeyInstance() );
}
return fetchBuilderMap;
@ -132,52 +182,69 @@ public class DynamicFetchBuilderLegacy
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 = tableGroup( fetchPath, attributeMapping, ownerTableGroup, creationState );
final TableGroup tableGroup = tableGroup( fetchPath, ownerTableGroup, creationState );
if ( lockMode != null ) {
domainResultCreationState.getSqlAstCreationState().registerLockMode( tableAlias, lockMode );
}
if ( columnNames != null ) {
final ForeignKeyDescriptor keyDescriptor = getForeignKeyDescriptor( attributeMapping );
if ( !columnNames.isEmpty() ) {
keyDescriptor.forEachSelectable( (selectionIndex, selectableMapping) -> {
resolveSqlSelection(
columnNames.get( selectionIndex ),
tableGroup.resolveTableReference(
fetchPath,
keyDescriptor.getKeyPart(),
selectableMapping.getContainingTableExpression()
),
selectableMapping,
jdbcResultsMetadata,
domainResultCreationState
); }
if ( fetchable instanceof EmbeddedAttributeMapping embeddedAttributeMapping ) {
embeddedAttributeMapping.forEachSelectable(
(selectionIndex, selectableMapping) ->
resolveSqlSelection(
columnNames.get( selectionIndex ),
tableGroup.resolveTableReference(
fetchPath,
(ValuedModelPart) selectableMapping,
selectableMapping.getContainingTableExpression()
),
selectableMapping,
jdbcResultsMetadata,
domainResultCreationState
)
);
}
else {
final ForeignKeyDescriptor keyDescriptor = getForeignKeyDescriptor( fetchable );
if ( !columnNames.isEmpty() ) {
keyDescriptor.forEachSelectable( (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 String prefix = DynamicResultBuilderEntityStandard.prefix( creationState, ELEMENT_PREFIX, 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,
@ -191,10 +258,9 @@ public class DynamicFetchBuilderLegacy
private TableGroup tableGroup(
NavigablePath fetchPath,
AttributeMapping attributeMapping,
TableGroup ownerTableGroup,
DomainResultCreationStateImpl creationState) {
if ( attributeMapping instanceof TableGroupJoinProducer tableGroupJoinProducer ) {
if ( fetchable instanceof TableGroupJoinProducer tableGroupJoinProducer ) {
final TableGroupJoin tableGroupJoin = tableGroupJoinProducer.createTableGroupJoin(
fetchPath,
ownerTableGroup,
@ -215,11 +281,11 @@ public class DynamicFetchBuilderLegacy
}
}
private static ForeignKeyDescriptor getForeignKeyDescriptor(AttributeMapping attributeMapping) {
if ( attributeMapping instanceof PluralAttributeMapping pluralAttributeMapping ) {
private static ForeignKeyDescriptor getForeignKeyDescriptor(Fetchable fetchable) {
if ( fetchable instanceof PluralAttributeMapping pluralAttributeMapping ) {
return pluralAttributeMapping.getKeyDescriptor();
}
else if ( attributeMapping instanceof ToOneAttributeMapping toOneAttributeMapping ) {
else if ( fetchable instanceof ToOneAttributeMapping toOneAttributeMapping ) {
return toOneAttributeMapping.getForeignKeyDescriptor();
}
else {
@ -228,6 +294,11 @@ public class DynamicFetchBuilderLegacy
}
}
@Override
public void visitFetchBuilders(BiConsumer<Fetchable, FetchBuilder> consumer) {
fetchBuilderMap.forEach( consumer );
}
private void resolveSqlSelection(
String columnAlias,
TableReference tableReference,
@ -262,32 +333,27 @@ public class DynamicFetchBuilderLegacy
}
@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;
}
@Override
public DynamicFetchBuilder addProperty(String propertyName) {
DynamicFetchBuilderStandard fetchBuilder = new DynamicFetchBuilderStandard( propertyName );
fetchBuilderMap.put( propertyName, fetchBuilder );
public DynamicFetchBuilder addProperty(Fetchable fetchable) {
DynamicFetchBuilderStandard fetchBuilder = new DynamicFetchBuilderStandard( fetchable );
fetchBuilderMap.put( fetchable, fetchBuilder );
return fetchBuilder;
}
@Override
public FetchBuilder findFetchBuilder(String fetchableName) {
return fetchBuilderMap.get( fetchableName );
public FetchBuilder findFetchBuilder(Fetchable fetchable) {
return fetchBuilderMap.get( fetchable );
}
@Override
public DynamicFetchBuilderContainer addProperty(String propertyName, String... columnAliases) {
final DynamicFetchBuilder fetchBuilder = addProperty( propertyName );
public DynamicFetchBuilderContainer addProperty(Fetchable fetchable, String columnAlias) {
final DynamicFetchBuilder fetchBuilder = addProperty( fetchable );
fetchBuilder.addColumnAlias( columnAlias );
return this;
}
@Override
public DynamicFetchBuilderContainer addProperty(Fetchable fetchable, String... columnAliases) {
final DynamicFetchBuilder fetchBuilder = addProperty( fetchable );
for ( String columnAlias : columnAliases ) {
fetchBuilder.addColumnAlias( columnAlias );
}
@ -295,13 +361,8 @@ public class DynamicFetchBuilderLegacy
}
@Override
public void addFetchBuilder(String propertyName, FetchBuilder fetchBuilder) {
fetchBuilderMap.put( propertyName, fetchBuilder );
}
@Override
public void visitFetchBuilders(BiConsumer<String, FetchBuilder> consumer) {
fetchBuilderMap.forEach( consumer );
public void addFetchBuilder(Fetchable fetchable, FetchBuilder fetchBuilder) {
fetchBuilderMap.put( fetchable, fetchBuilder );
}
@Override
@ -316,7 +377,8 @@ public class DynamicFetchBuilderLegacy
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 +388,8 @@ public class DynamicFetchBuilderLegacy
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 );

View File

@ -36,30 +36,29 @@ import java.util.List;
public class DynamicFetchBuilderStandard
implements DynamicFetchBuilder, NativeQuery.ReturnProperty {
private final String fetchableName;
private Fetchable fetchable;
private final List<String> 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<String> columnNames) {
this.fetchableName = fetchableName;
private DynamicFetchBuilderStandard(Fetchable fetchable, List<String> 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 )
);
}
@ -74,14 +73,12 @@ public class DynamicFetchBuilderStandard
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,
@ -93,7 +90,7 @@ public class DynamicFetchBuilderStandard
)
);
return parent.generateFetchableFetch(
attributeMapping,
fetchable,
fetchPath,
FetchTiming.IMMEDIATE,
true,
@ -101,8 +98,8 @@ public class DynamicFetchBuilderStandard
creationStateImpl
);
}
else if ( attributeMapping instanceof EmbeddableValuedFetchable ) {
attributeMapping.forEachSelectable(
else if ( fetchable instanceof EmbeddableValuedFetchable embeddableValuedFetchable ) {
fetchable.forEachSelectable(
getSelectableConsumer(
fetchPath,
jdbcResultsMetadata,
@ -110,11 +107,11 @@ public class DynamicFetchBuilderStandard
creationStateImpl,
ownerTableGroup,
sqlExpressionResolver,
(EmbeddableValuedFetchable) attributeMapping
embeddableValuedFetchable
)
);
return parent.generateFetchableFetch(
attributeMapping,
fetchable,
fetchPath,
FetchTiming.IMMEDIATE,
false,
@ -122,7 +119,7 @@ public class DynamicFetchBuilderStandard
creationStateImpl
);
}
else if ( attributeMapping instanceof ToOneAttributeMapping toOneAttributeMapping ) {
else if ( fetchable instanceof ToOneAttributeMapping toOneAttributeMapping ) {
toOneAttributeMapping.getForeignKeyDescriptor()
.getPart( toOneAttributeMapping.getSideNature() )
.forEachSelectable(
@ -137,15 +134,15 @@ public class DynamicFetchBuilderStandard
)
);
return parent.generateFetchableFetch(
attributeMapping,
fetchable,
fetchPath,
attributeMapping.getMappedFetchOptions().getTiming(),
fetchable.getMappedFetchOptions().getTiming(),
false,
null,
creationStateImpl
);
}
else if ( attributeMapping instanceof PluralAttributeMapping pluralAttributeMapping ) {
else if ( fetchable instanceof PluralAttributeMapping pluralAttributeMapping ) {
pluralAttributeMapping.getKeyDescriptor().visitTargetSelectables(
getSelectableConsumer(
fetchPath,
@ -158,9 +155,9 @@ public class DynamicFetchBuilderStandard
)
);
return parent.generateFetchableFetch(
attributeMapping,
fetchable,
fetchPath,
attributeMapping.getMappedFetchOptions().getTiming(),
fetchable.getMappedFetchOptions().getTiming(),
false,
null,
creationStateImpl
@ -215,7 +212,7 @@ public class DynamicFetchBuilderStandard
@Override
public int hashCode() {
int result = fetchableName.hashCode();
int result = fetchable.hashCode();
result = 31 * result + columnNames.hashCode();
return result;
}
@ -230,7 +227,7 @@ public class DynamicFetchBuilderStandard
}
final DynamicFetchBuilderStandard that = (DynamicFetchBuilderStandard) o;
return fetchableName.equals( that.fetchableName )
return fetchable.equals( that.fetchable )
&& columnNames.equals( that.columnNames );
}
}

View File

@ -7,13 +7,12 @@ package org.hibernate.query.results.internal.dynamic;
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.FetchBuilder;
import org.hibernate.query.results.internal.DomainResultCreationStateImpl;
@ -34,7 +33,6 @@ import org.hibernate.sql.results.jdbc.spi.JdbcValuesMetadata;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.Function;
@ -48,9 +46,6 @@ public class DynamicResultBuilderEntityStandard
extends AbstractFetchBuilderContainer<DynamicResultBuilderEntityStandard>
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;
@ -84,18 +79,6 @@ public class DynamicResultBuilderEntityStandard
this.discriminatorColumnName = original.discriminatorColumnName;
}
static String prefix(DomainResultCreationStateImpl creationState, String elementPrefix, String indexPrefix) {
final Map.Entry<String, NavigablePath> currentRelativePath = creationState.getCurrentRelativePath();
if ( currentRelativePath == null ) {
return "";
}
else {
return currentRelativePath.getKey()
.replace( elementPrefix, "" )
.replace( indexPrefix, "" ) + ".";
}
}
@Override
public Class<?> getJavaType() {
return entityMapping.getJavaType().getJavaTypeClass();
@ -277,7 +260,7 @@ public class DynamicResultBuilderEntityStandard
}
if ( discriminatorColumnName != null ) {
resolveSqlSelection(
resolveDiscriminatorSqlSelection(
discriminatorColumnName,
tableReference,
entityMapping.getDiscriminatorMapping(),
@ -287,18 +270,10 @@ public class DynamicResultBuilderEntityStandard
}
try {
final String prefix = prefix( creationState, ELEMENT_PREFIX, 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 +285,27 @@ public class DynamicResultBuilderEntityStandard
}
}
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 +344,18 @@ public class DynamicResultBuilderEntityStandard
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();

View File

@ -15,6 +15,7 @@ import org.hibernate.sql.ast.spi.SqlSelection;
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,9 +43,7 @@ public class ImplicitFetchBuilderBasic implements ImplicitFetchBuilder, FetchBui
DomainResultCreationState creationState) {
this.fetchPath = fetchPath;
this.fetchable = fetchable;
this.fetchBuilder =
impl( creationState ).getCurrentExplicitFetchMementoResolver()
.apply( fetchable.getFetchableName() );
this.fetchBuilder = impl( creationState ).getCurrentExplicitFetchMementoResolver().apply( fetchable );
}
@Override
@ -135,9 +134,9 @@ public class ImplicitFetchBuilderBasic implements ImplicitFetchBuilder, FetchBui
}
@Override
public void visitFetchBuilders(BiConsumer<String, FetchBuilder> consumer) {
public void visitFetchBuilders(BiConsumer<Fetchable, FetchBuilder> consumer) {
if ( fetchBuilder != null ) {
consumer.accept( fetchPath.getLocalName(), fetchBuilder );
consumer.accept( fetchable, fetchBuilder );
}
}
}

View File

@ -34,7 +34,7 @@ import static org.hibernate.query.results.internal.ResultsHelper.impl;
public class ImplicitFetchBuilderEmbeddable implements ImplicitFetchBuilder {
private final NavigablePath fetchPath;
private final EmbeddableValuedFetchable fetchable;
private final Map<NavigablePath, FetchBuilder> fetchBuilders;
private final Map<Fetchable, FetchBuilder> fetchBuilders;
public ImplicitFetchBuilderEmbeddable(
NavigablePath fetchPath,
@ -45,20 +45,18 @@ public class ImplicitFetchBuilderEmbeddable implements ImplicitFetchBuilder {
this.fetchBuilders = fetchBuilderMap( fetchPath, fetchable, impl( creationState ) );
}
private static Map<NavigablePath, FetchBuilder> fetchBuilderMap(
private static Map<Fetchable, FetchBuilder> fetchBuilderMap(
NavigablePath fetchPath,
EmbeddableValuedFetchable fetchable,
DomainResultCreationStateImpl creationStateImpl) {
final Function<String, FetchBuilder> fetchBuilderResolver =
final Function<Fetchable, FetchBuilder> fetchBuilderResolver =
creationStateImpl.getCurrentExplicitFetchMementoResolver();
final Map.Entry<String, NavigablePath> relativePath = creationStateImpl.getCurrentRelativePath();
final int size = fetchable.getNumberOfFetchables();
final Map<NavigablePath, FetchBuilder> fetchBuilders = linkedMapOfSize( size );
final Map<Fetchable, FetchBuilder> fetchBuilders = 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() );
fetchBuilders.put( subFetchPath,
final FetchBuilder explicitFetchBuilder = fetchBuilderResolver.apply( subFetchable );
fetchBuilders.put( subFetchable,
explicitFetchBuilder == null
? implicitFetchBuilder( fetchPath, subFetchable, creationStateImpl )
: explicitFetchBuilder );
@ -74,7 +72,7 @@ public class ImplicitFetchBuilderEmbeddable implements ImplicitFetchBuilder {
}
else {
fetchBuilders = new HashMap<>( original.fetchBuilders.size() );
for ( Map.Entry<NavigablePath, FetchBuilder> entry : original.fetchBuilders.entrySet() ) {
for ( Map.Entry<Fetchable, FetchBuilder> entry : original.fetchBuilders.entrySet() ) {
fetchBuilders.put( entry.getKey(), entry.getValue().cacheKeyInstance() );
}
}
@ -169,7 +167,7 @@ public class ImplicitFetchBuilderEmbeddable implements ImplicitFetchBuilder {
}
@Override
public void visitFetchBuilders(BiConsumer<String, FetchBuilder> consumer) {
fetchBuilders.forEach( (k, v) -> consumer.accept( k.getLocalName(), v ) );
public void visitFetchBuilders(BiConsumer<Fetchable, FetchBuilder> consumer) {
fetchBuilders.forEach( (k, v) -> consumer.accept( k, v ) );
}
}

View File

@ -34,7 +34,7 @@ import static org.hibernate.query.results.internal.ResultsHelper.impl;
public class ImplicitFetchBuilderEntity implements ImplicitFetchBuilder {
private final NavigablePath fetchPath;
private final ToOneAttributeMapping fetchable;
private final Map<NavigablePath, FetchBuilder> fetchBuilders;
private final Map<Fetchable, FetchBuilder> fetchBuilders;
public ImplicitFetchBuilderEntity(
NavigablePath fetchPath,
@ -43,30 +43,28 @@ public class ImplicitFetchBuilderEntity implements ImplicitFetchBuilder {
this.fetchPath = fetchPath;
this.fetchable = fetchable;
final DomainResultCreationStateImpl creationStateImpl = impl( creationState );
final Map.Entry<String, NavigablePath> relativePath = creationStateImpl.getCurrentRelativePath();
final Function<String, FetchBuilder> fetchBuilderResolver = creationStateImpl.getCurrentExplicitFetchMementoResolver();
final Function<Fetchable, FetchBuilder> fetchBuilderResolver = creationStateImpl.getCurrentExplicitFetchMementoResolver();
final 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 : split( ".", associationKeyPropertyName ) ) {
path = path.append( part );
keyName = part;
}
associationKeyFetchPath = path;
associationKey = (Fetchable) fetchable.findSubPart( keyName );
}
final FetchBuilder explicitAssociationKeyFetchBuilder =
fetchBuilderResolver.apply( relativePath.getKey() + "." + associationKeyPropertyName );
fetchBuilderResolver.apply( fetchable);
if ( explicitAssociationKeyFetchBuilder == null ) {
if ( foreignKeyDescriptor.getPartMappingType() instanceof EmbeddableMappingType embeddableType ) {
fetchBuilders = fetchBuilderMap(
fetchPath,
associationKeyFetchPath,
fetchBuilderResolver,
creationStateImpl,
embeddableType
@ -77,22 +75,21 @@ public class ImplicitFetchBuilderEntity implements ImplicitFetchBuilder {
}
}
else {
fetchBuilders = singletonMap( associationKeyFetchPath, explicitAssociationKeyFetchBuilder );
fetchBuilders = singletonMap( associationKey, explicitAssociationKeyFetchBuilder );
}
}
private static Map<NavigablePath, FetchBuilder> fetchBuilderMap(
NavigablePath fetchPath, NavigablePath associationKeyFetchPath,
Function<String, FetchBuilder> fetchBuilderResolver,
private static Map<Fetchable, FetchBuilder> fetchBuilderMap(
NavigablePath fetchPath,
Function<Fetchable, FetchBuilder> fetchBuilderResolver,
DomainResultCreationStateImpl creationStateImpl,
EmbeddableMappingType embeddableValuedModelPart) {
final int size = embeddableValuedModelPart.getNumberOfFetchables();
final Map<NavigablePath, FetchBuilder> fetchBuilders = linkedMapOfSize( size );
final Map<Fetchable, FetchBuilder> fetchBuilders = 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() );
fetchBuilders.put( subFetchPath,
final FetchBuilder explicitFetchBuilder = fetchBuilderResolver.apply( subFetchable );
fetchBuilders.put( subFetchable,
explicitFetchBuilder == null
? Builders.implicitFetchBuilder( fetchPath, subFetchable, creationStateImpl )
: explicitFetchBuilder );
@ -108,7 +105,7 @@ public class ImplicitFetchBuilderEntity implements ImplicitFetchBuilder {
}
else {
fetchBuilders = new HashMap<>( original.fetchBuilders.size() );
for ( Map.Entry<NavigablePath, FetchBuilder> entry : original.fetchBuilders.entrySet() ) {
for ( Map.Entry<Fetchable, FetchBuilder> entry : original.fetchBuilders.entrySet() ) {
fetchBuilders.put( entry.getKey(), entry.getValue().cacheKeyInstance() );
}
}
@ -136,8 +133,8 @@ public class ImplicitFetchBuilderEntity implements ImplicitFetchBuilder {
}
@Override
public void visitFetchBuilders(BiConsumer<String, FetchBuilder> consumer) {
fetchBuilders.forEach( (k, v) -> consumer.accept( k.getLocalName(), v ) );
public void visitFetchBuilders(BiConsumer<Fetchable, FetchBuilder> consumer) {
fetchBuilders.forEach( (k, v) -> consumer.accept( k, v ) );
}
@Override

View File

@ -9,6 +9,7 @@ import java.time.Instant;
import java.util.Calendar;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
@ -23,6 +24,12 @@ import org.hibernate.FlushMode;
import org.hibernate.jpa.spi.NativeQueryConstructorTransformer;
import org.hibernate.jpa.spi.NativeQueryListTransformer;
import org.hibernate.jpa.spi.NativeQueryMapTransformer;
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.metamodel.spi.MappingMetamodelImplementor;
import org.hibernate.query.QueryFlushMode;
import org.hibernate.HibernateException;
@ -90,6 +97,7 @@ import org.hibernate.query.sql.spi.ParameterOccurrence;
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.spi.SingleResultConsumer;
import org.hibernate.transform.ResultTransformer;
import org.hibernate.type.BasicType;
@ -140,6 +148,7 @@ public class NativeQueryImpl<R>
private final Class<R> resultType;
private final ResultSetMapping resultSetMapping;
private final boolean resultMappingSuppliedToCtor;
private final HashMap<String, EntityMappingType> entityMappingTypeByTableAlias = new HashMap<>();
private final QueryOptionsImpl queryOptions = new QueryOptionsImpl();
@ -1093,6 +1102,7 @@ public class NativeQueryImpl<R>
final DynamicResultBuilderEntityStandard resultBuilder =
Builders.entity( tableAlias, entityName, getSessionFactory() );
resultSetMapping.addResultBuilder( resultBuilder );
entityMappingTypeByTableAlias.put( tableAlias, resultBuilder.getEntityMapping() );
return resultBuilder;
}
@ -1108,13 +1118,19 @@ public class NativeQueryImpl<R>
@Override
public NativeQueryImplementor<R> 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<R> 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;
}
@ -1140,11 +1156,29 @@ public class NativeQueryImpl<R>
@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<R> addJoin(String tableAlias, String path) {
createFetchJoin( tableAlias, path );

View File

@ -21,11 +21,12 @@ import org.hibernate.internal.CoreLogging;
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.LegacyFetchBuilder;
@ -35,6 +36,7 @@ import org.hibernate.query.results.internal.dynamic.DynamicFetchBuilderContainer
import org.hibernate.query.results.internal.dynamic.DynamicFetchBuilderLegacy;
import org.hibernate.query.results.internal.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;
@ -133,7 +135,7 @@ public class ResultSetMappingProcessor implements SQLQueryParser.ParserContext {
return this;
}
private void processFetchBuilder(String attributeName, FetchBuilder fetchBuilder) {
private void processFetchBuilder(Fetchable attributeName, FetchBuilder fetchBuilder) {
if ( fetchBuilder instanceof LegacyFetchBuilder ) {
resultSetMapping.addLegacyFetchBuilder( (LegacyFetchBuilder) fetchBuilder );
}
@ -230,7 +232,7 @@ public class ResultSetMappingProcessor implements SQLQueryParser.ParserContext {
final EntityPersister loadable = alias2Persister.get( fetchBuilder.getOwnerAlias() );
final List<String> columnNames;
final String[] columnAliases = loadable.getSubclassPropertyColumnAliases(
fetchBuilder.getFetchableName(),
fetchBuilder.getFetchable().getFetchableName(),
alias2Suffix.get( fetchBuilder.getOwnerAlias() )
);
if ( columnAliases.length == 0 ) {
@ -244,7 +246,7 @@ public class ResultSetMappingProcessor implements SQLQueryParser.ParserContext {
columnNames = Arrays.asList( keyColumnAliases );
if ( collectionPersister.hasIndex() ) {
resultBuilderEntity.addProperty(
CollectionPart.Nature.INDEX.getName(),
((PluralAttributeMapping) fetchBuilder.getFetchable()).getIndexDescriptor(),
collectionPersister.getIndexColumnAliases( collectionSuffix )
);
}
@ -254,11 +256,11 @@ public class ResultSetMappingProcessor implements SQLQueryParser.ParserContext {
columnNames = Arrays.asList( columnAliases );
}
ownerBuilder.addFetchBuilder(
fetchBuilder.getFetchableName(),
fetchBuilder.getFetchable(),
new DynamicFetchBuilderLegacy(
fetchBuilder.getTableAlias(),
fetchBuilder.getOwnerAlias(),
fetchBuilder.getFetchableName(),
fetchBuilder.getFetchable(),
columnNames,
Collections.emptyMap(),
resultBuilderEntity
@ -273,11 +275,11 @@ public class ResultSetMappingProcessor implements SQLQueryParser.ParserContext {
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() );
}
}
@ -311,28 +313,33 @@ public class ResultSetMappingProcessor implements SQLQueryParser.ParserContext {
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;
}
@ -342,7 +349,7 @@ public class ResultSetMappingProcessor implements SQLQueryParser.ParserContext {
DynamicFetchBuilderContainer resultBuilderEntity,
String tableAlias,
String[] identifierAliases,
String propertyName,
Fetchable fetchable,
String[] columnAliases,
Type propertyType) {
if ( propertyType instanceof CollectionType collectionType ) {
@ -356,15 +363,15 @@ public class ResultSetMappingProcessor implements SQLQueryParser.ParserContext {
suffix
);
}
resultBuilderEntity.addProperty( propertyName, keyColumnAliases );
resultBuilderEntity.addProperty( fetchable, keyColumnAliases );
}
else if ( propertyType instanceof ComponentType componentType ) {
final Map<String, FetchBuilder> fetchBuilderMap = new HashMap<>();
final Map<Fetchable, FetchBuilder> fetchBuilderMap = new HashMap<>();
final DynamicFetchBuilderLegacy fetchBuilder = new DynamicFetchBuilderLegacy(
"",
tableAlias,
propertyName,
null,
fetchable,
Arrays.asList( columnAliases ),
fetchBuilderMap
);
final String[] propertyNames = componentType.getPropertyNames();
@ -378,28 +385,28 @@ public class ResultSetMappingProcessor implements SQLQueryParser.ParserContext {
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 );
}
}
@ -560,10 +567,10 @@ public class ResultSetMappingProcessor implements SQLQueryParser.ParserContext {
}
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<String, String[]> propertyResultsMap = Collections.emptyMap();//fetchReturn.getPropertyResultsMap()
addCollection( role, alias, propertyResultsMap );
// collectionOwnerAliases.add( ownerAlias );

View File

@ -6,6 +6,7 @@ package org.hibernate.sql.ast.spi;
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 @@ public interface SqlExpressionResolver {
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 ),