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
parent a2d4e27467
commit b565d2b3af
24 changed files with 510 additions and 436 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(
@ -274,7 +274,7 @@ public class Builders {
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 ) {

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

@ -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;
@ -135,7 +136,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;
@ -165,7 +166,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,21 +11,22 @@ 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() {
}
protected AbstractFetchBuilderContainer(AbstractFetchBuilderContainer<T> original) {
if ( original.fetchBuilderMap != null ) {
final Map<String, FetchBuilder> fetchBuilderMap = new HashMap<>( original.fetchBuilderMap.size() );
for ( Map.Entry<String, FetchBuilder> entry : original.fetchBuilderMap.entrySet() ) {
final Map<Fetchable, FetchBuilder> fetchBuilderMap = new HashMap<>( original.fetchBuilderMap.size() );
for ( Map.Entry<Fetchable, FetchBuilder> entry : original.fetchBuilderMap.entrySet() ) {
final FetchBuilder fetchBuilder;
if ( entry.getValue() instanceof DynamicFetchBuilderStandard ) {
fetchBuilder = ( (DynamicFetchBuilderStandard) entry.getValue() ).cacheKeyInstance( this );
@ -42,40 +43,38 @@ 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
)
);
@ -83,19 +82,20 @@ public abstract class AbstractFetchBuilderContainer<T extends AbstractFetchBuild
}
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

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

@ -6,11 +6,14 @@ package org.hibernate.query.results.internal.dynamic;
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;
@ -45,39 +49,37 @@ import static org.hibernate.query.results.internal.ResultsHelper.impl;
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;
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;
@ -93,27 +95,72 @@ 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) {
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<String, FetchBuilder> fetchBuilderMap;
final Map<Fetchable, FetchBuilder> fetchBuilderMap;
if ( this.fetchBuilderMap == null ) {
fetchBuilderMap = null;
}
else {
fetchBuilderMap = new HashMap<>( this.fetchBuilderMap.size() );
for ( Map.Entry<String, FetchBuilder> entry : this.fetchBuilderMap.entrySet() ) {
for ( Map.Entry<Fetchable, FetchBuilder> 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()
@ -128,13 +175,10 @@ 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;
if ( attributeMapping instanceof TableGroupJoinProducer ) {
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,67 +195,73 @@ public class DynamicFetchBuilderLegacy
tableGroup = ownerTableGroup;
}
if ( columnNames != null ) {
if ( !columnNames.isEmpty() ) {
final ForeignKeyDescriptor keyDescriptor;
if ( attributeMapping instanceof PluralAttributeMapping pluralAttributeMapping ) {
keyDescriptor = pluralAttributeMapping.getKeyDescriptor();
}
else {
// Not sure if this fetch builder can also be used with other attribute mappings
assert attributeMapping instanceof ToOneAttributeMapping;
final ToOneAttributeMapping toOneAttributeMapping = (ToOneAttributeMapping) attributeMapping;
keyDescriptor = toOneAttributeMapping.getForeignKeyDescriptor();
}
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 {
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) fetchable;
keyDescriptor = toOneAttributeMapping.getForeignKeyDescriptor();
}
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 Map.Entry<String, NavigablePath> 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,
@ -223,6 +273,11 @@ public class DynamicFetchBuilderLegacy
}
}
@Override
public void visitFetchBuilders(BiConsumer<Fetchable, FetchBuilder> consumer) {
fetchBuilderMap.forEach( consumer );
}
private void resolveSqlSelection(
String columnAlias,
TableReference tableReference,
@ -259,32 +314,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 );
}
@ -292,13 +342,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
@ -313,7 +358,7 @@ 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 )
&& Objects.equals( columnNames, that.columnNames )
&& Objects.equals( fetchBuilderMap, that.fetchBuilderMap )
&& Objects.equals( resultBuilderEntity, that.resultBuilderEntity );
@ -323,7 +368,7 @@ 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 + ( columnNames != null ? columnNames.hashCode() : 0 );
result = 31 * result + ( fetchBuilderMap != null ? fetchBuilderMap.hashCode() : 0 );
result = 31 * result + ( resultBuilderEntity != null ? resultBuilderEntity.hashCode() : 0 );

View File

@ -35,30 +35,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 )
);
}
@ -72,13 +71,11 @@ public class DynamicFetchBuilderStandard
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,
@ -90,7 +87,7 @@ public class DynamicFetchBuilderStandard
)
);
return parent.generateFetchableFetch(
attributeMapping,
fetchable,
fetchPath,
FetchTiming.IMMEDIATE,
true,
@ -98,8 +95,8 @@ public class DynamicFetchBuilderStandard
creationStateImpl
);
}
else if ( attributeMapping instanceof EmbeddableValuedFetchable ) {
attributeMapping.forEachSelectable(
else if ( fetchable instanceof EmbeddableValuedFetchable embeddableValuedFetchable ) {
fetchable.forEachSelectable(
getSelectableConsumer(
fetchPath,
jdbcResultsMetadata,
@ -107,11 +104,11 @@ public class DynamicFetchBuilderStandard
creationStateImpl,
ownerTableGroup,
sqlExpressionResolver,
(EmbeddableValuedFetchable) attributeMapping
embeddableValuedFetchable
)
);
return parent.generateFetchableFetch(
attributeMapping,
fetchable,
fetchPath,
FetchTiming.IMMEDIATE,
false,
@ -119,7 +116,7 @@ public class DynamicFetchBuilderStandard
creationStateImpl
);
}
else if ( attributeMapping instanceof ToOneAttributeMapping toOneAttributeMapping ) {
else if ( fetchable instanceof ToOneAttributeMapping toOneAttributeMapping ) {
toOneAttributeMapping.getForeignKeyDescriptor().getPart( toOneAttributeMapping.getSideNature() )
.forEachSelectable(
getSelectableConsumer(
@ -133,17 +130,17 @@ public class DynamicFetchBuilderStandard
)
);
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,
@ -156,9 +153,9 @@ public class DynamicFetchBuilderStandard
)
);
return parent.generateFetchableFetch(
attributeMapping,
fetchable,
fetchPath,
attributeMapping.getMappedFetchOptions().getTiming(),
fetchable.getMappedFetchOptions().getTiming(),
false,
null,
creationStateImpl
@ -212,7 +209,7 @@ public class DynamicFetchBuilderStandard
@Override
public int hashCode() {
int result = fetchableName.hashCode();
int result = fetchable.hashCode();
result = 31 * result + columnNames.hashCode();
return result;
}
@ -227,7 +224,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,11 @@ 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.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 +32,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 +45,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;
@ -275,27 +269,10 @@ public class DynamicResultBuilderEntityStandard
}
try {
final Map.Entry<String, NavigablePath> 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;
}
@ -308,11 +285,7 @@ public class DynamicResultBuilderEntityStandard
}
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(
@ -351,6 +324,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

@ -16,6 +16,7 @@ import org.hibernate.sql.ast.tree.expression.Expression;
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;
@ -40,13 +41,14 @@ public class ImplicitFetchBuilderBasic implements ImplicitFetchBuilder, FetchBui
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<String, FetchBuilder> fetchBuilderResolver = creationStateImpl.getCurrentExplicitFetchMementoResolver();
this.fetchBuilder = fetchBuilderResolver.apply( fetchable.getFetchableName() );
final Function<Fetchable, FetchBuilder> fetchBuilderResolver = creationStateImpl.getCurrentExplicitFetchMementoResolver();
this.fetchBuilder = fetchBuilderResolver.apply( fetchable );
}
@Override
@ -141,9 +143,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,
@ -43,22 +43,20 @@ public class ImplicitFetchBuilderEmbeddable 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 int size = fetchable.getNumberOfFetchables();
final Map<NavigablePath, FetchBuilder> fetchBuilders = CollectionHelper.linkedMapOfSize( size );
final Map<Fetchable, FetchBuilder> 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;
@ -67,13 +65,13 @@ public class ImplicitFetchBuilderEmbeddable implements ImplicitFetchBuilder {
private ImplicitFetchBuilderEmbeddable(ImplicitFetchBuilderEmbeddable original) {
this.fetchPath = original.fetchPath;
this.fetchable = original.fetchable;
final Map<NavigablePath, FetchBuilder> fetchBuilders;
final Map<Fetchable, FetchBuilder> fetchBuilders;
if ( original.fetchBuilders.isEmpty() ) {
fetchBuilders = Collections.emptyMap();
}
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() );
}
}
@ -165,7 +163,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,26 +43,25 @@ 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();
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<NavigablePath, FetchBuilder> fetchBuilders;
.apply( fetchable );
final Map<Fetchable, FetchBuilder> fetchBuilders;
if ( explicitAssociationKeyFetchBuilder == null ) {
final MappingType partMappingType = foreignKeyDescriptor.getPartMappingType();
if ( partMappingType instanceof EmbeddableMappingType embeddableValuedModelPart ) {
@ -70,16 +69,15 @@ public class ImplicitFetchBuilderEntity implements ImplicitFetchBuilder {
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 );
}
}
}
@ -88,7 +86,7 @@ public class ImplicitFetchBuilderEntity implements ImplicitFetchBuilder {
}
}
else {
fetchBuilders = Collections.singletonMap( associationKeyFetchPath, explicitAssociationKeyFetchBuilder );
fetchBuilders = Collections.singletonMap( associationKey, explicitAssociationKeyFetchBuilder );
}
this.fetchBuilders = fetchBuilders;
}
@ -96,13 +94,13 @@ public class ImplicitFetchBuilderEntity implements ImplicitFetchBuilder {
private ImplicitFetchBuilderEntity(ImplicitFetchBuilderEntity original) {
this.fetchPath = original.fetchPath;
this.fetchable = original.fetchable;
final Map<NavigablePath, FetchBuilder> fetchBuilders;
final Map<Fetchable, FetchBuilder> fetchBuilders;
if ( original.fetchBuilders.isEmpty() ) {
fetchBuilders = Collections.emptyMap();
}
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() );
}
}
@ -131,8 +129,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;
@ -19,6 +20,12 @@ import java.util.function.Supplier;
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.metamodel.spi.MappingMetamodelImplementor;
import org.hibernate.query.QueryFlushMode;
import org.hibernate.HibernateException;
@ -86,6 +93,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;
@ -131,6 +139,7 @@ public class NativeQueryImpl<R>
private final ResultSetMapping resultSetMapping;
private final boolean resultMappingSuppliedToCtor;
private final HashMap<String, EntityMappingType> entityMappingTypeByTableAlias = new HashMap<>();
private final QueryOptionsImpl queryOptions = new QueryOptionsImpl();
@ -1007,6 +1016,7 @@ public class NativeQueryImpl<R>
final DynamicResultBuilderEntityStandard resultBuilder =
Builders.entity( tableAlias, entityName, getSessionFactory() );
resultSetMapping.addResultBuilder( resultBuilder );
entityMappingTypeByTableAlias.put( tableAlias, resultBuilder.getEntityMapping() );
return resultBuilder;
}
@ -1022,13 +1032,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;
}
@ -1054,11 +1070,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

@ -9,6 +9,7 @@ import java.util.function.Function;
import org.hibernate.metamodel.mapping.JdbcMapping;
import org.hibernate.metamodel.mapping.SelectableMapping;
import org.hibernate.metamodel.mapping.SelectablePath;
import org.hibernate.metamodel.mapping.internal.DiscriminatorTypeImpl;
import org.hibernate.sql.ast.tree.expression.ColumnReference;
import org.hibernate.sql.ast.tree.expression.Expression;
import org.hibernate.sql.ast.tree.expression.NestedColumnReference;
@ -126,7 +127,12 @@ public interface SqlExpressionResolver {
public ColumnReferenceKey(String tableQualifier, SelectablePath selectablePath, JdbcMapping jdbcMapping) {
this.tableQualifier = tableQualifier;
this.selectablePath = selectablePath;
this.jdbcMapping = jdbcMapping;
if ( jdbcMapping instanceof DiscriminatorTypeImpl discriminatorType ) {
this.jdbcMapping = discriminatorType.getUnderlyingJdbcMapping();
}
else {
this.jdbcMapping = jdbcMapping;
}
}
@Override