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:
parent
cd47e91900
commit
49886d1fd5
|
@ -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";
|
||||
|
|
|
@ -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();
|
||||
|
||||
/**
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
);
|
||||
}
|
||||
|
|
|
@ -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 )
|
||||
)
|
||||
);
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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 );
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 ) );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 );
|
||||
|
|
|
@ -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 );
|
||||
|
|
|
@ -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 ),
|
||||
|
|
Loading…
Reference in New Issue