HHH-15879 Introduce a fetchable key for Fetchable within FetchableContainer

This commit is contained in:
Christian Beikov 2022-12-15 12:50:29 +01:00
parent 69091d1394
commit 37ec41d319
74 changed files with 851 additions and 377 deletions

View File

@ -56,6 +56,7 @@ import org.hibernate.sql.results.graph.Fetch;
import org.hibernate.sql.results.graph.FetchParent; import org.hibernate.sql.results.graph.FetchParent;
import org.hibernate.sql.results.graph.Fetchable; import org.hibernate.sql.results.graph.Fetchable;
import org.hibernate.sql.results.graph.FetchableContainer; import org.hibernate.sql.results.graph.FetchableContainer;
import org.hibernate.sql.results.graph.internal.ImmutableFetchList;
import org.hibernate.sql.results.spi.ListResultsConsumer; import org.hibernate.sql.results.spi.ListResultsConsumer;
import org.hibernate.stat.spi.StatisticsImplementor; import org.hibernate.stat.spi.StatisticsImplementor;
@ -413,12 +414,12 @@ public abstract class AbstractNaturalIdLoader<T> implements NaturalIdLoader<T> {
return results.get( 0 ); return results.get( 0 );
} }
private static List<Fetch> visitFetches( private static ImmutableFetchList visitFetches(
FetchParent fetchParent, FetchParent fetchParent,
LoaderSqlAstCreationState creationState) { LoaderSqlAstCreationState creationState) {
final FetchableContainer fetchableContainer = fetchParent.getReferencedMappingContainer(); final FetchableContainer fetchableContainer = fetchParent.getReferencedMappingContainer();
final int size = fetchableContainer.getNumberOfFetchables(); final int size = fetchableContainer.getNumberOfFetchables();
final List<Fetch> fetches = new ArrayList<>( size ); final ImmutableFetchList.Builder fetches = new ImmutableFetchList.Builder( fetchableContainer );
for ( int i = 0; i < size; i++ ) { for ( int i = 0; i < size; i++ ) {
final Fetchable fetchable = fetchableContainer.getFetchable( i ); final Fetchable fetchable = fetchableContainer.getFetchable( i );
final NavigablePath navigablePath = fetchParent.resolveNavigablePath( fetchable ); final NavigablePath navigablePath = fetchParent.resolveNavigablePath( fetchable );
@ -432,6 +433,6 @@ public abstract class AbstractNaturalIdLoader<T> implements NaturalIdLoader<T> {
); );
fetches.add( fetch ); fetches.add( fetch );
} }
return fetches; return fetches.build();
} }
} }

View File

@ -41,6 +41,7 @@ import org.hibernate.sql.exec.spi.ExecutionContext;
import org.hibernate.sql.exec.spi.JdbcOperationQuerySelect; import org.hibernate.sql.exec.spi.JdbcOperationQuerySelect;
import org.hibernate.sql.exec.spi.JdbcParameterBindings; import org.hibernate.sql.exec.spi.JdbcParameterBindings;
import org.hibernate.sql.results.graph.DomainResult; import org.hibernate.sql.results.graph.DomainResult;
import org.hibernate.sql.results.graph.internal.ImmutableFetchList;
import org.hibernate.sql.results.internal.RowTransformerDatabaseSnapshotImpl; import org.hibernate.sql.results.internal.RowTransformerDatabaseSnapshotImpl;
import org.hibernate.sql.results.spi.ListResultsConsumer; import org.hibernate.sql.results.spi.ListResultsConsumer;
import org.hibernate.type.BasicType; import org.hibernate.type.BasicType;
@ -76,7 +77,7 @@ class DatabaseSnapshotExecutor {
sqlAliasBaseManager, sqlAliasBaseManager,
new FromClauseIndex( null ), new FromClauseIndex( null ),
LockOptions.NONE, LockOptions.NONE,
(fetchParent, creationState) -> Collections.emptyList(), (fetchParent, creationState) -> ImmutableFetchList.EMPTY,
true, true,
sessionFactory sessionFactory
); );

View File

@ -83,6 +83,7 @@ import org.hibernate.sql.results.graph.Fetchable;
import org.hibernate.sql.results.graph.FetchableContainer; import org.hibernate.sql.results.graph.FetchableContainer;
import org.hibernate.sql.results.graph.collection.internal.CollectionDomainResult; import org.hibernate.sql.results.graph.collection.internal.CollectionDomainResult;
import org.hibernate.sql.results.graph.entity.EntityValuedFetchable; import org.hibernate.sql.results.graph.entity.EntityValuedFetchable;
import org.hibernate.sql.results.graph.internal.ImmutableFetchList;
import org.hibernate.sql.results.internal.SqlSelectionImpl; import org.hibernate.sql.results.internal.SqlSelectionImpl;
import org.hibernate.sql.results.internal.StandardEntityGraphTraversalStateImpl; import org.hibernate.sql.results.internal.StandardEntityGraphTraversalStateImpl;
@ -648,12 +649,12 @@ public class LoaderSelectBuilder {
orderByFragments.add( new AbstractMap.SimpleEntry<>( orderByFragment, tableGroup ) ); orderByFragments.add( new AbstractMap.SimpleEntry<>( orderByFragment, tableGroup ) );
} }
private List<Fetch> visitFetches(FetchParent fetchParent, LoaderSqlAstCreationState creationState) { private ImmutableFetchList visitFetches(FetchParent fetchParent, LoaderSqlAstCreationState creationState) {
if ( log.isTraceEnabled() ) { if ( log.isTraceEnabled() ) {
log.tracef( "Starting visitation of FetchParent's Fetchables : %s", fetchParent.getNavigablePath() ); log.tracef( "Starting visitation of FetchParent's Fetchables : %s", fetchParent.getNavigablePath() );
} }
final List<Fetch> fetches = new ArrayList<>(); final ImmutableFetchList.Builder fetches = new ImmutableFetchList.Builder( fetchParent.getReferencedMappingContainer() );
final BiConsumer<Fetchable, Boolean> processor = createFetchableBiConsumer( final BiConsumer<Fetchable, Boolean> processor = createFetchableBiConsumer(
fetchParent, fetchParent,
creationState, creationState,
@ -671,13 +672,13 @@ public class LoaderSelectBuilder {
for ( int i = 0; i < size; i++ ) { for ( int i = 0; i < size; i++ ) {
processor.accept( referencedMappingContainer.getFetchable( i ), false ); processor.accept( referencedMappingContainer.getFetchable( i ), false );
} }
return fetches; return fetches.build();
} }
private BiConsumer<Fetchable, Boolean> createFetchableBiConsumer( private BiConsumer<Fetchable, Boolean> createFetchableBiConsumer(
FetchParent fetchParent, FetchParent fetchParent,
LoaderSqlAstCreationState creationState, LoaderSqlAstCreationState creationState,
List<Fetch> fetches) { ImmutableFetchList.Builder fetches) {
return (fetchable, isKeyFetchable) -> { return (fetchable, isKeyFetchable) -> {
final NavigablePath fetchablePath; final NavigablePath fetchablePath;

View File

@ -38,6 +38,7 @@ import org.hibernate.sql.ast.tree.select.QueryPart;
import org.hibernate.sql.results.graph.DomainResultCreationState; import org.hibernate.sql.results.graph.DomainResultCreationState;
import org.hibernate.sql.results.graph.Fetch; import org.hibernate.sql.results.graph.Fetch;
import org.hibernate.sql.results.graph.FetchParent; import org.hibernate.sql.results.graph.FetchParent;
import org.hibernate.sql.results.graph.internal.ImmutableFetchList;
/** /**
* Helper used when generating the database-snapshot select query * Helper used when generating the database-snapshot select query
@ -45,7 +46,7 @@ import org.hibernate.sql.results.graph.FetchParent;
public class LoaderSqlAstCreationState public class LoaderSqlAstCreationState
implements SqlAstQueryPartProcessingState, SqlAstCreationState, DomainResultCreationState, QueryOptions { implements SqlAstQueryPartProcessingState, SqlAstCreationState, DomainResultCreationState, QueryOptions {
public interface FetchProcessor { public interface FetchProcessor {
List<Fetch> visitFetches(FetchParent fetchParent, LoaderSqlAstCreationState creationState); ImmutableFetchList visitFetches(FetchParent fetchParent, LoaderSqlAstCreationState creationState);
} }
private final SqlAliasBaseManager sqlAliasBaseManager; private final SqlAliasBaseManager sqlAliasBaseManager;
@ -119,15 +120,15 @@ public class LoaderSqlAstCreationState
} }
@Override @Override
public List<Fetch> visitFetches(FetchParent fetchParent) { public ImmutableFetchList visitFetches(FetchParent fetchParent) {
return fetchProcessor.visitFetches( fetchParent, this ); return fetchProcessor.visitFetches( fetchParent, this );
} }
@Override @Override
public List<Fetch> visitNestedFetches(FetchParent fetchParent) { public ImmutableFetchList visitNestedFetches(FetchParent fetchParent) {
final FetchParent nestingFetchParent = processingState.getNestingFetchParent(); final FetchParent nestingFetchParent = processingState.getNestingFetchParent();
processingState.setNestingFetchParent( fetchParent ); processingState.setNestingFetchParent( fetchParent );
final List<Fetch> fetches = fetchProcessor.visitFetches( fetchParent, this ); final ImmutableFetchList fetches = fetchProcessor.visitFetches( fetchParent, this );
processingState.setNestingFetchParent( nestingFetchParent ); processingState.setNestingFetchParent( nestingFetchParent );
return fetches; return fetches;
} }

View File

@ -14,4 +14,8 @@ import org.hibernate.metamodel.mapping.internal.SingleAttributeIdentifierMapping
* @author Steve Ebersole * @author Steve Ebersole
*/ */
public interface BasicEntityIdentifierMapping extends SingleAttributeIdentifierMapping, BasicValuedModelPart { public interface BasicEntityIdentifierMapping extends SingleAttributeIdentifierMapping, BasicValuedModelPart {
@Override
default int getFetchableKey() {
return -1;
}
} }

View File

@ -16,6 +16,11 @@ import org.hibernate.engine.spi.IdentifierValue;
*/ */
public interface CompositeIdentifierMapping extends EntityIdentifierMapping, EmbeddableValuedModelPart { public interface CompositeIdentifierMapping extends EntityIdentifierMapping, EmbeddableValuedModelPart {
@Override
default int getFetchableKey() {
return -1;
}
@Override @Override
default IdentifierValue getUnsavedStrategy() { default IdentifierValue getUnsavedStrategy() {
return IdentifierValue.UNDEFINED; return IdentifierValue.UNDEFINED;

View File

@ -42,6 +42,11 @@ public interface EntityDiscriminatorMapping extends VirtualModelPart, BasicValue
return getPartName(); return getPartName();
} }
@Override
default int getFetchableKey() {
return -2;
}
DiscriminatorType getDiscriminatorType(); DiscriminatorType getDiscriminatorType();
String getConcreteEntityNameForDiscriminatorValue(Object value); String getConcreteEntityNameForDiscriminatorValue(Object value);

View File

@ -45,6 +45,11 @@ public interface NonAggregatedIdentifierMapping extends CompositeIdentifierMappi
*/ */
IdentifierValueMapper getIdentifierValueMapper(); IdentifierValueMapper getIdentifierValueMapper();
@Override
default int getFetchableKey() {
return -1;
}
/** /**
* Think of an AttributeConverter for id values to account for representation * Think of an AttributeConverter for id values to account for representation
* difference between virtual and id-class mappings * difference between virtual and id-class mappings

View File

@ -99,6 +99,11 @@ public interface PluralAttributeMapping
return 1; return 1;
} }
@Override
default int getNumberOfFetchableKeys() {
return getNumberOfKeyFetchables() + getNumberOfFetchables();
}
@Override @Override
default void visitFetchables(IndexedConsumer<? super Fetchable> fetchableConsumer, EntityMappingType treatTargetType) { default void visitFetchables(IndexedConsumer<? super Fetchable> fetchableConsumer, EntityMappingType treatTargetType) {
fetchableConsumer.accept( 0, getElementDescriptor() ); fetchableConsumer.accept( 0, getElementDescriptor() );

View File

@ -17,11 +17,13 @@ import org.hibernate.type.descriptor.java.JavaType;
*/ */
public abstract class AbstractAttributeMapping implements AttributeMapping { public abstract class AbstractAttributeMapping implements AttributeMapping {
private final String name; private final String name;
private final int fetchableIndex;
private final ManagedMappingType declaringType; private final ManagedMappingType declaringType;
public AbstractAttributeMapping(String name, ManagedMappingType declaringType) { public AbstractAttributeMapping(String name, int fetchableIndex, ManagedMappingType declaringType) {
this.name = name; this.name = name;
this.fetchableIndex = fetchableIndex;
this.declaringType = declaringType; this.declaringType = declaringType;
} }
@ -35,6 +37,11 @@ public abstract class AbstractAttributeMapping implements AttributeMapping {
return name; return name;
} }
@Override
public int getFetchableKey() {
return fetchableIndex;
}
@Override @Override
public MappingType getPartMappingType() { public MappingType getPartMappingType() {
return getMappedType(); return getMappedType();

View File

@ -300,6 +300,7 @@ public abstract class AbstractEmbeddableMapping implements EmbeddableMappingType
bootPropertyDescriptor.getName(), bootPropertyDescriptor.getName(),
navigableRole.append( bootPropertyDescriptor.getName() ), navigableRole.append( bootPropertyDescriptor.getName() ),
attributeIndex, attributeIndex,
attributeIndex,
bootPropertyDescriptor, bootPropertyDescriptor,
declarer, declarer,
(BasicType<?>) subtype, (BasicType<?>) subtype,
@ -380,6 +381,7 @@ public abstract class AbstractEmbeddableMapping implements EmbeddableMappingType
typeConfiguration.getJavaTypeRegistry().getDescriptor( Object.class ), typeConfiguration.getJavaTypeRegistry().getDescriptor( Object.class ),
declarer, declarer,
attributeIndex, attributeIndex,
attributeIndex,
attributeMetadataAccess, attributeMetadataAccess,
bootPropertyDescriptor.isLazy() ? FetchTiming.DELAYED : FetchTiming.IMMEDIATE, bootPropertyDescriptor.isLazy() ? FetchTiming.DELAYED : FetchTiming.IMMEDIATE,
propertyAccess, propertyAccess,
@ -407,6 +409,7 @@ public abstract class AbstractEmbeddableMapping implements EmbeddableMappingType
attributeMapping = MappingModelCreationHelper.buildEmbeddedAttributeMapping( attributeMapping = MappingModelCreationHelper.buildEmbeddedAttributeMapping(
bootPropertyDescriptor.getName(), bootPropertyDescriptor.getName(),
attributeIndex, attributeIndex,
attributeIndex,
bootPropertyDescriptor, bootPropertyDescriptor,
declarer, declarer,
subCompositeType, subCompositeType,
@ -426,6 +429,7 @@ public abstract class AbstractEmbeddableMapping implements EmbeddableMappingType
attributeMapping = MappingModelCreationHelper.buildPluralAttributeMapping( attributeMapping = MappingModelCreationHelper.buildPluralAttributeMapping(
bootPropertyDescriptor.getName(), bootPropertyDescriptor.getName(),
attributeIndex, attributeIndex,
attributeIndex,
bootPropertyDescriptor, bootPropertyDescriptor,
entityPersister, entityPersister,
propertyAccess, propertyAccess,
@ -442,6 +446,7 @@ public abstract class AbstractEmbeddableMapping implements EmbeddableMappingType
bootPropertyDescriptor.getName(), bootPropertyDescriptor.getName(),
navigableRole.append( bootPropertyDescriptor.getName() ), navigableRole.append( bootPropertyDescriptor.getName() ),
attributeIndex, attributeIndex,
attributeIndex,
bootPropertyDescriptor, bootPropertyDescriptor,
entityPersister, entityPersister,
entityPersister, entityPersister,

View File

@ -114,6 +114,11 @@ public abstract class AbstractEntityCollectionPart implements EntityCollectionPa
return nature.getName(); return nature.getName();
} }
@Override
public int getFetchableKey() {
return nature == Nature.INDEX || !collectionDescriptor.hasIndex() ? 0 : 1;
}
@Override @Override
public EntityMappingType getAssociatedEntityMappingType() { public EntityMappingType getAssociatedEntityMappingType() {
return associatedEntityTypeDescriptor; return associatedEntityTypeDescriptor;

View File

@ -27,23 +27,25 @@ public abstract class AbstractSingularAttributeMapping
public AbstractSingularAttributeMapping( public AbstractSingularAttributeMapping(
String name, String name,
int stateArrayPosition, int stateArrayPosition,
int fetchableIndex,
AttributeMetadata attributeMetadata, AttributeMetadata attributeMetadata,
FetchOptions mappedFetchOptions, FetchOptions mappedFetchOptions,
ManagedMappingType declaringType, ManagedMappingType declaringType,
PropertyAccess propertyAccess) { PropertyAccess propertyAccess) {
super( name, attributeMetadata, mappedFetchOptions, stateArrayPosition, declaringType ); super( name, attributeMetadata, mappedFetchOptions, stateArrayPosition, fetchableIndex, declaringType );
this.propertyAccess = propertyAccess; this.propertyAccess = propertyAccess;
} }
public AbstractSingularAttributeMapping( public AbstractSingularAttributeMapping(
String name, String name,
int stateArrayPosition, int stateArrayPosition,
int fetchableIndex,
AttributeMetadata attributeMetadata, AttributeMetadata attributeMetadata,
FetchTiming fetchTiming, FetchTiming fetchTiming,
FetchStyle fetchStyle, FetchStyle fetchStyle,
ManagedMappingType declaringType, ManagedMappingType declaringType,
PropertyAccess propertyAccess) { PropertyAccess propertyAccess) {
super( name, attributeMetadata, fetchTiming, fetchStyle, stateArrayPosition, declaringType ); super( name, attributeMetadata, fetchTiming, fetchStyle, stateArrayPosition, fetchableIndex, declaringType );
this.propertyAccess = propertyAccess; this.propertyAccess = propertyAccess;
} }

View File

@ -30,8 +30,9 @@ public abstract class AbstractStateArrayContributorMapping
FetchTiming fetchTiming, FetchTiming fetchTiming,
FetchStyle fetchStyle, FetchStyle fetchStyle,
int stateArrayPosition, int stateArrayPosition,
int fetchableIndex,
ManagedMappingType declaringType) { ManagedMappingType declaringType) {
super( name, declaringType ); super( name, fetchableIndex, declaringType );
this.attributeMetadata = attributeMetadata; this.attributeMetadata = attributeMetadata;
this.fetchTiming = fetchTiming; this.fetchTiming = fetchTiming;
this.fetchStyle = fetchStyle; this.fetchStyle = fetchStyle;
@ -43,6 +44,7 @@ public abstract class AbstractStateArrayContributorMapping
AttributeMetadata attributeMetadata, AttributeMetadata attributeMetadata,
FetchOptions mappedFetchOptions, FetchOptions mappedFetchOptions,
int stateArrayPosition, int stateArrayPosition,
int fetchableIndex,
ManagedMappingType declaringType) { ManagedMappingType declaringType) {
this( this(
name, name,
@ -50,6 +52,7 @@ public abstract class AbstractStateArrayContributorMapping
mappedFetchOptions.getTiming(), mappedFetchOptions.getTiming(),
mappedFetchOptions.getStyle(), mappedFetchOptions.getStyle(),
stateArrayPosition, stateArrayPosition,
fetchableIndex,
declaringType declaringType
); );
} }

View File

@ -59,8 +59,8 @@ public class AnyDiscriminatorPart implements BasicValuedModelPart, FetchOptions,
private final Integer precision; private final Integer precision;
private final Integer scale; private final Integer scale;
private boolean isInsertable; private final boolean insertable;
private boolean isUpdateable; private final boolean updateable;
private final MetaType metaType; private final MetaType metaType;
public AnyDiscriminatorPart( public AnyDiscriminatorPart(
@ -83,8 +83,8 @@ public class AnyDiscriminatorPart implements BasicValuedModelPart, FetchOptions,
this.length = length; this.length = length;
this.precision = precision; this.precision = precision;
this.scale = scale; this.scale = scale;
this.isInsertable = insertable; this.insertable = insertable;
this.isUpdateable = updateable; this.updateable = updateable;
this.metaType = metaType; this.metaType = metaType;
} }
@ -118,12 +118,12 @@ public class AnyDiscriminatorPart implements BasicValuedModelPart, FetchOptions,
@Override @Override
public boolean isInsertable() { public boolean isInsertable() {
return isInsertable; return insertable;
} }
@Override @Override
public boolean isUpdateable() { public boolean isUpdateable() {
return isUpdateable; return updateable;
} }
@Override @Override
@ -235,6 +235,11 @@ public class AnyDiscriminatorPart implements BasicValuedModelPart, FetchOptions,
return getPartName(); return getPartName();
} }
@Override
public int getFetchableKey() {
return 0;
}
@Override @Override
public FetchOptions getMappedFetchOptions() { public FetchOptions getMappedFetchOptions() {
return this; return this;

View File

@ -54,8 +54,8 @@ public class AnyKeyPart implements BasicValuedModelPart, FetchOptions {
private final Integer precision; private final Integer precision;
private final Integer scale; private final Integer scale;
private final boolean nullable; private final boolean nullable;
private boolean isInsertable; private final boolean insertable;
private boolean isUpdateable; private final boolean updateable;
private final JdbcMapping jdbcMapping; private final JdbcMapping jdbcMapping;
public AnyKeyPart( public AnyKeyPart(
@ -80,8 +80,8 @@ public class AnyKeyPart implements BasicValuedModelPart, FetchOptions {
this.precision = precision; this.precision = precision;
this.scale = scale; this.scale = scale;
this.nullable = nullable; this.nullable = nullable;
this.isInsertable = insertable; this.insertable = insertable;
this.isUpdateable = updateable; this.updateable = updateable;
this.jdbcMapping = jdbcMapping; this.jdbcMapping = jdbcMapping;
} }
@ -107,12 +107,12 @@ public class AnyKeyPart implements BasicValuedModelPart, FetchOptions {
@Override @Override
public boolean isInsertable() { public boolean isInsertable() {
return isInsertable; return insertable;
} }
@Override @Override
public boolean isUpdateable() { public boolean isUpdateable() {
return isUpdateable; return updateable;
} }
@Override @Override
@ -180,6 +180,11 @@ public class AnyKeyPart implements BasicValuedModelPart, FetchOptions {
return getPartName(); return getPartName();
} }
@Override
public int getFetchableKey() {
return 1;
}
@Override @Override
public FetchOptions getMappedFetchOptions() { public FetchOptions getMappedFetchOptions() {
return this; return this;

View File

@ -69,6 +69,7 @@ public class BasicAttributeMapping
String attributeName, String attributeName,
NavigableRole navigableRole, NavigableRole navigableRole,
int stateArrayPosition, int stateArrayPosition,
int fetchableIndex,
AttributeMetadata attributeMetadata, AttributeMetadata attributeMetadata,
FetchTiming mappedFetchTiming, FetchTiming mappedFetchTiming,
FetchStyle mappedFetchStyle, FetchStyle mappedFetchStyle,
@ -91,6 +92,7 @@ public class BasicAttributeMapping
super( super(
attributeName, attributeName,
stateArrayPosition, stateArrayPosition,
fetchableIndex,
attributeMetadata, attributeMetadata,
mappedFetchTiming, mappedFetchTiming,
mappedFetchStyle, mappedFetchStyle,
@ -155,6 +157,7 @@ public class BasicAttributeMapping
attributeName, attributeName,
original.getNavigableRole(), original.getNavigableRole(),
stateArrayPosition, stateArrayPosition,
original.getFetchableKey(),
attributeMetadata, attributeMetadata,
FetchTiming.IMMEDIATE, FetchTiming.IMMEDIATE,
FetchStyle.JOIN, FetchStyle.JOIN,

View File

@ -232,6 +232,11 @@ public class BasicValuedCollectionPart
return nature.getName(); return nature.getName();
} }
@Override
public int getFetchableKey() {
return nature == Nature.INDEX || !collectionDescriptor.hasIndex() ? 0 : 1;
}
@Override @Override
public FetchOptions getMappedFetchOptions() { public FetchOptions getMappedFetchOptions() {
return this; return this;

View File

@ -206,6 +206,11 @@ public class CollectionIdentifierDescriptorImpl implements CollectionIdentifierD
return null; return null;
} }
@Override
public int getFetchableKey() {
return -1;
}
@Override @Override
public FetchOptions getMappedFetchOptions() { public FetchOptions getMappedFetchOptions() {
return this; return this;

View File

@ -8,7 +8,6 @@ package org.hibernate.metamodel.mapping.internal;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.function.BiConsumer; import java.util.function.BiConsumer;
@ -19,7 +18,6 @@ import org.hibernate.NotYetImplementedFor6Exception;
import org.hibernate.engine.spi.PersistenceContext; import org.hibernate.engine.spi.PersistenceContext;
import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.engine.spi.SharedSessionContractImplementor; import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.internal.util.collections.CollectionHelper;
import org.hibernate.loader.ast.internal.CompoundNaturalIdLoader; import org.hibernate.loader.ast.internal.CompoundNaturalIdLoader;
import org.hibernate.loader.ast.internal.MultiNaturalIdLoaderStandard; import org.hibernate.loader.ast.internal.MultiNaturalIdLoaderStandard;
import org.hibernate.loader.ast.spi.MultiNaturalIdLoader; import org.hibernate.loader.ast.spi.MultiNaturalIdLoader;
@ -48,6 +46,7 @@ import org.hibernate.sql.results.graph.FetchParentAccess;
import org.hibernate.sql.results.graph.Fetchable; import org.hibernate.sql.results.graph.Fetchable;
import org.hibernate.sql.results.graph.FetchableContainer; import org.hibernate.sql.results.graph.FetchableContainer;
import org.hibernate.sql.results.graph.entity.EntityInitializer; import org.hibernate.sql.results.graph.entity.EntityInitializer;
import org.hibernate.sql.results.graph.internal.ImmutableFetchList;
import org.hibernate.sql.results.jdbc.spi.JdbcValuesSourceProcessingOptions; import org.hibernate.sql.results.jdbc.spi.JdbcValuesSourceProcessingOptions;
import org.hibernate.sql.results.jdbc.spi.RowProcessingState; import org.hibernate.sql.results.jdbc.spi.RowProcessingState;
import org.hibernate.type.descriptor.java.JavaType; import org.hibernate.type.descriptor.java.JavaType;
@ -453,7 +452,9 @@ public class CompoundNaturalIdMapping extends AbstractNaturalIdMapping implement
private final CompoundNaturalIdMapping naturalIdMapping; private final CompoundNaturalIdMapping naturalIdMapping;
private final JavaType<Object[]> arrayJtd; private final JavaType<Object[]> arrayJtd;
private final List<Fetch> fetches; private final ImmutableFetchList fetches;
private final boolean hasJoinFetches;
private final boolean containsCollectionFetches;
private final String resultVariable; private final String resultVariable;
@ -468,7 +469,9 @@ public class CompoundNaturalIdMapping extends AbstractNaturalIdMapping implement
this.arrayJtd = arrayJtd; this.arrayJtd = arrayJtd;
this.resultVariable = resultVariable; this.resultVariable = resultVariable;
this.fetches = Collections.unmodifiableList( creationState.visitFetches( this ) ); this.fetches = creationState.visitFetches( this );
this.hasJoinFetches = this.fetches.hasJoinFetches();
this.containsCollectionFetches = this.fetches.containsCollectionFetches();
} }
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@ -517,22 +520,24 @@ public class CompoundNaturalIdMapping extends AbstractNaturalIdMapping implement
} }
@Override @Override
public List<Fetch> getFetches() { public ImmutableFetchList getFetches() {
return fetches; return fetches;
} }
@Override @Override
public Fetch findFetch(Fetchable fetchable) { public Fetch findFetch(Fetchable fetchable) {
assert fetchable != null; assert fetchable != null;
return fetches.get( fetchable );
for ( int i = 0; i < fetches.size(); i++ ) {
final Fetch fetch = fetches.get( i );
if ( fetchable.equals( fetch.getFetchedMapping() ) ) {
return fetch;
}
} }
return null; @Override
public boolean hasJoinFetches() {
return hasJoinFetches;
}
@Override
public boolean containsCollectionFetches() {
return containsCollectionFetches;
} }
} }
@ -541,10 +546,10 @@ public class CompoundNaturalIdMapping extends AbstractNaturalIdMapping implement
private final CompoundNaturalIdMapping naturalIdMapping; private final CompoundNaturalIdMapping naturalIdMapping;
private final JavaType<Object[]> jtd; private final JavaType<Object[]> jtd;
private final List<DomainResultAssembler<?>> subAssemblers; private final DomainResultAssembler<?>[] subAssemblers;
private AssemblerImpl( private AssemblerImpl(
List<Fetch> fetches, ImmutableFetchList fetches,
NavigablePath navigablePath, NavigablePath navigablePath,
CompoundNaturalIdMapping naturalIdMapping, CompoundNaturalIdMapping naturalIdMapping,
JavaType<Object[]> jtd, JavaType<Object[]> jtd,
@ -557,11 +562,10 @@ public class CompoundNaturalIdMapping extends AbstractNaturalIdMapping implement
// we just "need it" as an impl detail for handling Fetches // we just "need it" as an impl detail for handling Fetches
final InitializerImpl initializer = new InitializerImpl( navigablePath, naturalIdMapping ); final InitializerImpl initializer = new InitializerImpl( navigablePath, naturalIdMapping );
this.subAssemblers = CollectionHelper.arrayList( fetches.size() ); this.subAssemblers = new DomainResultAssembler[fetches.size()];
for ( int i = 0; i < fetches.size(); i++ ) { int i = 0;
final Fetch fetch = fetches.get( i ); for ( Fetch fetch : fetches ) {
final DomainResultAssembler<?> fetchAssembler = fetch.createAssembler( initializer, creationState ); subAssemblers[i++] = fetch.createAssembler( initializer, creationState );
subAssemblers.add( fetchAssembler );
} }
} }
@ -569,9 +573,9 @@ public class CompoundNaturalIdMapping extends AbstractNaturalIdMapping implement
public Object[] assemble( public Object[] assemble(
RowProcessingState rowProcessingState, RowProcessingState rowProcessingState,
JdbcValuesSourceProcessingOptions options) { JdbcValuesSourceProcessingOptions options) {
final Object[] result = new Object[ subAssemblers.size() ]; final Object[] result = new Object[ subAssemblers.length ];
for ( int i = 0; i < subAssemblers.size(); i++ ) { for ( int i = 0; i < subAssemblers.length; i++ ) {
result[ i ] = subAssemblers.get( i ).assemble( rowProcessingState, options ); result[ i ] = subAssemblers[i].assemble( rowProcessingState, options );
} }
return result; return result;
} }

View File

@ -71,6 +71,7 @@ public class DiscriminatedAssociationAttributeMapping
JavaType<?> baseAssociationJtd, JavaType<?> baseAssociationJtd,
ManagedMappingType declaringType, ManagedMappingType declaringType,
int stateArrayPosition, int stateArrayPosition,
int fetchableIndex,
AttributeMetadata attributeMetadata, AttributeMetadata attributeMetadata,
FetchTiming fetchTiming, FetchTiming fetchTiming,
PropertyAccess propertyAccess, PropertyAccess propertyAccess,
@ -81,6 +82,7 @@ public class DiscriminatedAssociationAttributeMapping
super( super(
bootProperty.getName(), bootProperty.getName(),
stateArrayPosition, stateArrayPosition,
fetchableIndex,
attributeMetadata, attributeMetadata,
fetchTiming, fetchTiming,
FetchStyle.SELECT, FetchStyle.SELECT,
@ -188,8 +190,10 @@ public class DiscriminatedAssociationAttributeMapping
public Fetchable getFetchable(int position) { public Fetchable getFetchable(int position) {
switch ( position ) { switch ( position ) {
case 0: case 0:
assert getDiscriminatorPart().getFetchableKey() == 0;
return getDiscriminatorPart(); return getDiscriminatorPart();
case 1: case 1:
assert getKeyPart().getFetchableKey() == 1;
return getKeyPart(); return getKeyPart();
} }
throw new IndexOutOfBoundsException(position); throw new IndexOutOfBoundsException(position);

View File

@ -44,6 +44,7 @@ import org.hibernate.sql.results.graph.FetchOptions;
import org.hibernate.sql.results.graph.FetchParent; import org.hibernate.sql.results.graph.FetchParent;
import org.hibernate.sql.results.graph.FetchParentAccess; import org.hibernate.sql.results.graph.FetchParentAccess;
import org.hibernate.sql.results.graph.Fetchable; import org.hibernate.sql.results.graph.Fetchable;
import org.hibernate.sql.results.graph.internal.ImmutableFetchList;
import org.hibernate.sql.results.jdbc.spi.JdbcValuesSourceProcessingOptions; import org.hibernate.sql.results.jdbc.spi.JdbcValuesSourceProcessingOptions;
import org.hibernate.sql.results.jdbc.spi.RowProcessingState; import org.hibernate.sql.results.jdbc.spi.RowProcessingState;
import org.hibernate.type.AnyType; import org.hibernate.type.AnyType;
@ -413,7 +414,7 @@ public class DiscriminatedAssociationMapping implements MappingType, FetchOption
private Fetch discriminatorValueFetch; private Fetch discriminatorValueFetch;
private Fetch keyValueFetch; private Fetch keyValueFetch;
private List<Fetch> fetches; private ImmutableFetchList fetches;
public AnyValuedResultGraphNode( public AnyValuedResultGraphNode(
NavigablePath navigablePath, NavigablePath navigablePath,
@ -425,11 +426,11 @@ public class DiscriminatedAssociationMapping implements MappingType, FetchOption
} }
protected void afterInitialize(DomainResultCreationState creationState) { protected void afterInitialize(DomainResultCreationState creationState) {
this.fetches = Collections.unmodifiableList( creationState.visitFetches( this ) ); this.fetches = creationState.visitFetches( this );
assert fetches.size() == 2; assert fetches.size() == 2;
discriminatorValueFetch = fetches.get( 0 ); discriminatorValueFetch = fetches.get( graphedPart.getDiscriminatorPart() );
keyValueFetch = fetches.get( 1 ); keyValueFetch = fetches.get( graphedPart.getKeyPart() );
} }
public Fetch getDiscriminatorValueFetch() { public Fetch getDiscriminatorValueFetch() {
@ -470,7 +471,7 @@ public class DiscriminatedAssociationMapping implements MappingType, FetchOption
} }
@Override @Override
public List<Fetch> getFetches() { public ImmutableFetchList getFetches() {
return fetches; return fetches;
} }
@ -486,6 +487,16 @@ public class DiscriminatedAssociationMapping implements MappingType, FetchOption
throw new IllegalArgumentException( "Given Fetchable [" + fetchable + "] did not match either discriminator nor key mapping" ); throw new IllegalArgumentException( "Given Fetchable [" + fetchable + "] did not match either discriminator nor key mapping" );
} }
@Override
public boolean hasJoinFetches() {
return false;
}
@Override
public boolean containsCollectionFetches() {
return false;
}
} }
private static class AnyValuedResult<T> extends AnyValuedResultGraphNode implements DomainResult<T> { private static class AnyValuedResult<T> extends AnyValuedResultGraphNode implements DomainResult<T> {

View File

@ -117,6 +117,11 @@ public class DiscriminatedCollectionPart implements DiscriminatedAssociationMode
return nature.getName(); return nature.getName();
} }
@Override
public int getFetchableKey() {
return nature == Nature.INDEX || !collectionDescriptor.hasIndex() ? 0 : 1;
}
@Override @Override
public FetchOptions getMappedFetchOptions() { public FetchOptions getMappedFetchOptions() {
return discriminatorMapping; return discriminatorMapping;

View File

@ -407,6 +407,7 @@ public class EmbeddableMappingTypeImpl extends AbstractEmbeddableMapping impleme
bootPropertyDescriptor.getName(), bootPropertyDescriptor.getName(),
valueMapping.getNavigableRole().append( bootPropertyDescriptor.getName() ), valueMapping.getNavigableRole().append( bootPropertyDescriptor.getName() ),
attributeIndex, attributeIndex,
attributeIndex,
bootPropertyDescriptor, bootPropertyDescriptor,
this, this,
(BasicType<?>) subtype, (BasicType<?>) subtype,
@ -488,6 +489,7 @@ public class EmbeddableMappingTypeImpl extends AbstractEmbeddableMapping impleme
typeConfiguration.getJavaTypeRegistry().getDescriptor( Object.class ), typeConfiguration.getJavaTypeRegistry().getDescriptor( Object.class ),
this, this,
attributeIndex, attributeIndex,
attributeIndex,
attributeMetadataAccess, attributeMetadataAccess,
bootPropertyDescriptor.isLazy() ? FetchTiming.DELAYED : FetchTiming.IMMEDIATE, bootPropertyDescriptor.isLazy() ? FetchTiming.DELAYED : FetchTiming.IMMEDIATE,
propertyAccess, propertyAccess,
@ -515,6 +517,7 @@ public class EmbeddableMappingTypeImpl extends AbstractEmbeddableMapping impleme
attributeMapping = MappingModelCreationHelper.buildEmbeddedAttributeMapping( attributeMapping = MappingModelCreationHelper.buildEmbeddedAttributeMapping(
bootPropertyDescriptor.getName(), bootPropertyDescriptor.getName(),
attributeIndex, attributeIndex,
attributeIndex,
bootPropertyDescriptor, bootPropertyDescriptor,
this, this,
subCompositeType, subCompositeType,
@ -533,6 +536,7 @@ public class EmbeddableMappingTypeImpl extends AbstractEmbeddableMapping impleme
attributeMapping = MappingModelCreationHelper.buildPluralAttributeMapping( attributeMapping = MappingModelCreationHelper.buildPluralAttributeMapping(
bootPropertyDescriptor.getName(), bootPropertyDescriptor.getName(),
attributeIndex, attributeIndex,
attributeIndex,
bootPropertyDescriptor, bootPropertyDescriptor,
entityPersister, entityPersister,
representationStrategy.resolvePropertyAccess( bootPropertyDescriptor ), representationStrategy.resolvePropertyAccess( bootPropertyDescriptor ),
@ -548,6 +552,7 @@ public class EmbeddableMappingTypeImpl extends AbstractEmbeddableMapping impleme
bootPropertyDescriptor.getName(), bootPropertyDescriptor.getName(),
valueMapping.getNavigableRole().append( bootPropertyDescriptor.getName() ), valueMapping.getNavigableRole().append( bootPropertyDescriptor.getName() ),
attributeIndex, attributeIndex,
attributeIndex,
bootPropertyDescriptor, bootPropertyDescriptor,
entityPersister, entityPersister,
entityPersister, entityPersister,

View File

@ -75,6 +75,7 @@ public class EmbeddedAttributeMapping
String name, String name,
NavigableRole navigableRole, NavigableRole navigableRole,
int stateArrayPosition, int stateArrayPosition,
int fetchableIndex,
String tableExpression, String tableExpression,
AttributeMetadata attributeMetadata, AttributeMetadata attributeMetadata,
String parentInjectionAttributeName, String parentInjectionAttributeName,
@ -87,6 +88,7 @@ public class EmbeddedAttributeMapping
name, name,
navigableRole, navigableRole,
stateArrayPosition, stateArrayPosition,
fetchableIndex,
tableExpression, tableExpression,
attributeMetadata, attributeMetadata,
getPropertyAccess( parentInjectionAttributeName, embeddableMappingType ), getPropertyAccess( parentInjectionAttributeName, embeddableMappingType ),
@ -102,6 +104,7 @@ public class EmbeddedAttributeMapping
String name, String name,
NavigableRole navigableRole, NavigableRole navigableRole,
int stateArrayPosition, int stateArrayPosition,
int fetchableIndex,
String tableExpression, String tableExpression,
AttributeMetadata attributeMetadata, AttributeMetadata attributeMetadata,
PropertyAccess parentInjectionAttributePropertyAccess, PropertyAccess parentInjectionAttributePropertyAccess,
@ -113,6 +116,7 @@ public class EmbeddedAttributeMapping
super( super(
name, name,
stateArrayPosition, stateArrayPosition,
fetchableIndex,
attributeMetadata, attributeMetadata,
mappedFetchTiming, mappedFetchTiming,
mappedFetchStyle, mappedFetchStyle,
@ -139,6 +143,7 @@ public class EmbeddedAttributeMapping
super( super(
inverseModelPart.getFetchableName(), inverseModelPart.getFetchableName(),
-1, -1,
inverseModelPart.getFetchableKey(),
null, null,
inverseModelPart.getMappedFetchOptions(), inverseModelPart.getMappedFetchOptions(),
keyDeclaringType, keyDeclaringType,

View File

@ -140,6 +140,11 @@ public class EmbeddedCollectionPart implements CollectionPart, EmbeddableValuedF
return getNature().getName(); return getNature().getName();
} }
@Override
public int getFetchableKey() {
return nature == Nature.INDEX || !collectionDescriptor.hasIndex() ? 0 : 1;
}
@Override @Override
public FetchOptions getMappedFetchOptions() { public FetchOptions getMappedFetchOptions() {
return this; return this;

View File

@ -207,6 +207,11 @@ public class EntityVersionMappingImpl implements EntityVersionMapping, FetchOpti
return attributeName; return attributeName;
} }
@Override
public int getFetchableKey() {
return getVersionAttribute().getFetchableKey();
}
@Override @Override
public FetchOptions getMappedFetchOptions() { public FetchOptions getMappedFetchOptions() {
return this; return this;

View File

@ -107,6 +107,7 @@ public class IdClassEmbeddable extends AbstractEmbeddableMapping implements Iden
.append( EntityIdentifierMapping.ROLE_LOCAL_NAME ) .append( EntityIdentifierMapping.ROLE_LOCAL_NAME )
.append( NavigablePath.IDENTIFIER_MAPPER_PROPERTY ), .append( NavigablePath.IDENTIFIER_MAPPER_PROPERTY ),
-1, -1,
-1,
idTable, idTable,
attributeMetadata, attributeMetadata,
(PropertyAccess) null, (PropertyAccess) null,

View File

@ -178,6 +178,7 @@ public class MappingModelCreationHelper {
String attrName, String attrName,
NavigableRole navigableRole, NavigableRole navigableRole,
int stateArrayPosition, int stateArrayPosition,
int fetchableIndex,
Property bootProperty, Property bootProperty,
ManagedMappingType declaringType, ManagedMappingType declaringType,
BasicType attrType, BasicType attrType,
@ -223,6 +224,7 @@ public class MappingModelCreationHelper {
attrName, attrName,
navigableRole, navigableRole,
stateArrayPosition, stateArrayPosition,
fetchableIndex,
attributeMetadata, attributeMetadata,
fetchTiming, fetchTiming,
fetchStyle, fetchStyle,
@ -249,6 +251,7 @@ public class MappingModelCreationHelper {
public static EmbeddedAttributeMapping buildEmbeddedAttributeMapping( public static EmbeddedAttributeMapping buildEmbeddedAttributeMapping(
String attrName, String attrName,
int stateArrayPosition, int stateArrayPosition,
int fetchableIndex,
Property bootProperty, Property bootProperty,
ManagedMappingType declaringType, ManagedMappingType declaringType,
CompositeType attrType, CompositeType attrType,
@ -280,6 +283,7 @@ public class MappingModelCreationHelper {
attrName, attrName,
declaringType.getNavigableRole().append( attrName ), declaringType.getNavigableRole().append( attrName ),
stateArrayPosition, stateArrayPosition,
fetchableIndex,
tableExpression, tableExpression,
attributeMetadataAccess, attributeMetadataAccess,
component.getParentProperty(), component.getParentProperty(),
@ -295,6 +299,7 @@ public class MappingModelCreationHelper {
attrName, attrName,
declaringType.getNavigableRole().append( attrName ), declaringType.getNavigableRole().append( attrName ),
stateArrayPosition, stateArrayPosition,
fetchableIndex,
tableExpression, tableExpression,
attributeMetadataAccess, attributeMetadataAccess,
component.getParentProperty(), component.getParentProperty(),
@ -373,6 +378,7 @@ public class MappingModelCreationHelper {
public static PluralAttributeMapping buildPluralAttributeMapping( public static PluralAttributeMapping buildPluralAttributeMapping(
String attrName, String attrName,
int stateArrayPosition, int stateArrayPosition,
int fetchableIndex,
Property bootProperty, Property bootProperty,
ManagedMappingType declaringType, ManagedMappingType declaringType,
PropertyAccess propertyAccess, PropertyAccess propertyAccess,
@ -578,6 +584,7 @@ public class MappingModelCreationHelper {
attributeMetadata, attributeMetadata,
collectionMappingType, collectionMappingType,
stateArrayPosition, stateArrayPosition,
fetchableIndex,
elementDescriptor, elementDescriptor,
indexDescriptor, indexDescriptor,
identifierDescriptor, identifierDescriptor,
@ -1492,6 +1499,7 @@ public class MappingModelCreationHelper {
String attrName, String attrName,
NavigableRole navigableRole, NavigableRole navigableRole,
int stateArrayPosition, int stateArrayPosition,
int fetchableIndex,
Property bootProperty, Property bootProperty,
ManagedMappingType declaringType, ManagedMappingType declaringType,
EntityPersister declaringEntityPersister, EntityPersister declaringEntityPersister,
@ -1546,6 +1554,7 @@ public class MappingModelCreationHelper {
attrName, attrName,
navigableRole, navigableRole,
stateArrayPosition, stateArrayPosition,
fetchableIndex,
(ToOne) bootProperty.getValue(), (ToOne) bootProperty.getValue(),
attributeMetadata, attributeMetadata,
fetchTiming, fetchTiming,

View File

@ -119,6 +119,7 @@ public class PluralAttributeMappingImpl
AttributeMetadata attributeMetadata, AttributeMetadata attributeMetadata,
CollectionMappingType<?> collectionMappingType, CollectionMappingType<?> collectionMappingType,
int stateArrayPosition, int stateArrayPosition,
int fetchableIndex,
CollectionPart elementDescriptor, CollectionPart elementDescriptor,
CollectionPart indexDescriptor, CollectionPart indexDescriptor,
CollectionIdentifierDescriptor identifierDescriptor, CollectionIdentifierDescriptor identifierDescriptor,
@ -127,7 +128,7 @@ public class PluralAttributeMappingImpl
CascadeStyle cascadeStyle, CascadeStyle cascadeStyle,
ManagedMappingType declaringType, ManagedMappingType declaringType,
CollectionPersister collectionDescriptor) { CollectionPersister collectionDescriptor) {
super( attributeName, declaringType ); super( attributeName, fetchableIndex, declaringType );
this.propertyAccess = propertyAccess; this.propertyAccess = propertyAccess;
this.attributeMetadata = attributeMetadata; this.attributeMetadata = attributeMetadata;
this.collectionMappingType = collectionMappingType; this.collectionMappingType = collectionMappingType;

View File

@ -581,6 +581,11 @@ public class SimpleForeignKeyDescriptor implements ForeignKeyDescriptor, BasicVa
return PART_NAME; return PART_NAME;
} }
@Override
public int getFetchableKey() {
throw new UnsupportedOperationException();
}
@Override @Override
public FetchOptions getMappedFetchOptions() { public FetchOptions getMappedFetchOptions() {
return this; return this;

View File

@ -160,6 +160,7 @@ public class ToOneAttributeMapping
String name, String name,
NavigableRole navigableRole, NavigableRole navigableRole,
int stateArrayPosition, int stateArrayPosition,
int fetchableIndex,
ToOne bootValue, ToOne bootValue,
AttributeMetadata attributeMetadata, AttributeMetadata attributeMetadata,
FetchOptions mappedFetchOptions, FetchOptions mappedFetchOptions,
@ -171,6 +172,7 @@ public class ToOneAttributeMapping
name, name,
navigableRole, navigableRole,
stateArrayPosition, stateArrayPosition,
fetchableIndex,
bootValue, bootValue,
attributeMetadata, attributeMetadata,
mappedFetchOptions.getTiming(), mappedFetchOptions.getTiming(),
@ -186,6 +188,7 @@ public class ToOneAttributeMapping
String name, String name,
NavigableRole navigableRole, NavigableRole navigableRole,
int stateArrayPosition, int stateArrayPosition,
int fetchableIndex,
ToOne bootValue, ToOne bootValue,
AttributeMetadata attributeMetadata, AttributeMetadata attributeMetadata,
FetchTiming mappedFetchTiming, FetchTiming mappedFetchTiming,
@ -197,6 +200,7 @@ public class ToOneAttributeMapping
super( super(
name, name,
stateArrayPosition, stateArrayPosition,
fetchableIndex,
attributeMetadata, attributeMetadata,
adjustFetchTiming( mappedFetchTiming, bootValue ), adjustFetchTiming( mappedFetchTiming, bootValue ),
mappedFetchStyle, mappedFetchStyle,
@ -548,6 +552,7 @@ public class ToOneAttributeMapping
super( super(
original.getAttributeName(), original.getAttributeName(),
original.getStateArrayPosition(), original.getStateArrayPosition(),
original.getFetchableKey(),
original.getAttributeMetadata(), original.getAttributeMetadata(),
original, original,
declaringType, declaringType,

View File

@ -27,6 +27,7 @@ public class VirtualEmbeddedAttributeMapping extends EmbeddedAttributeMapping im
String name, String name,
NavigableRole navigableRole, NavigableRole navigableRole,
int stateArrayPosition, int stateArrayPosition,
int fetchableIndex,
String tableExpression, String tableExpression,
AttributeMetadata attributeMetadata, AttributeMetadata attributeMetadata,
String parentInjectionAttributeName, String parentInjectionAttributeName,
@ -39,6 +40,7 @@ public class VirtualEmbeddedAttributeMapping extends EmbeddedAttributeMapping im
name, name,
navigableRole, navigableRole,
stateArrayPosition, stateArrayPosition,
fetchableIndex,
tableExpression, tableExpression,
attributeMetadata, attributeMetadata,
parentInjectionAttributeName, parentInjectionAttributeName,
@ -54,6 +56,7 @@ public class VirtualEmbeddedAttributeMapping extends EmbeddedAttributeMapping im
String name, String name,
NavigableRole navigableRole, NavigableRole navigableRole,
int stateArrayPosition, int stateArrayPosition,
int fetchableIndex,
String tableExpression, String tableExpression,
AttributeMetadata attributeMetadata, AttributeMetadata attributeMetadata,
PropertyAccess parentInjectionAttributePropertyAccess, PropertyAccess parentInjectionAttributePropertyAccess,
@ -66,6 +69,7 @@ public class VirtualEmbeddedAttributeMapping extends EmbeddedAttributeMapping im
name, name,
navigableRole, navigableRole,
stateArrayPosition, stateArrayPosition,
fetchableIndex,
tableExpression, tableExpression,
attributeMetadata, attributeMetadata,
parentInjectionAttributePropertyAccess, parentInjectionAttributePropertyAccess,

View File

@ -125,6 +125,7 @@ import org.hibernate.sql.model.internal.TableDeleteStandard;
import org.hibernate.sql.model.jdbc.JdbcDeleteMutation; import org.hibernate.sql.model.jdbc.JdbcDeleteMutation;
import org.hibernate.sql.model.jdbc.JdbcMutationOperation; import org.hibernate.sql.model.jdbc.JdbcMutationOperation;
import org.hibernate.sql.results.graph.DomainResult; import org.hibernate.sql.results.graph.DomainResult;
import org.hibernate.sql.results.graph.internal.ImmutableFetchList;
import org.hibernate.sql.results.internal.SqlSelectionImpl; import org.hibernate.sql.results.internal.SqlSelectionImpl;
import org.hibernate.generator.Generator; import org.hibernate.generator.Generator;
import org.hibernate.generator.InMemoryGenerator; import org.hibernate.generator.InMemoryGenerator;
@ -934,7 +935,7 @@ public abstract class AbstractCollectionPersister
new SqlAliasBaseManager(), new SqlAliasBaseManager(),
new SimpleFromClauseAccessImpl(), new SimpleFromClauseAccessImpl(),
LockOptions.NONE, LockOptions.NONE,
(fetchParent, creationState) -> new ArrayList<>(), (fetchParent, creationState) -> ImmutableFetchList.EMPTY,
true, true,
getFactory() getFactory()
); );

View File

@ -261,6 +261,7 @@ import org.hibernate.sql.results.graph.Fetchable;
import org.hibernate.sql.results.graph.FetchableContainer; import org.hibernate.sql.results.graph.FetchableContainer;
import org.hibernate.sql.results.graph.embeddable.EmbeddableResultGraphNode; import org.hibernate.sql.results.graph.embeddable.EmbeddableResultGraphNode;
import org.hibernate.sql.results.graph.entity.internal.EntityResultImpl; import org.hibernate.sql.results.graph.entity.internal.EntityResultImpl;
import org.hibernate.sql.results.graph.internal.ImmutableFetchList;
import org.hibernate.sql.results.internal.SqlSelectionImpl; import org.hibernate.sql.results.internal.SqlSelectionImpl;
import org.hibernate.stat.spi.StatisticsImplementor; import org.hibernate.stat.spi.StatisticsImplementor;
import org.hibernate.tuple.NonIdentifierAttribute; import org.hibernate.tuple.NonIdentifierAttribute;
@ -1797,10 +1798,10 @@ public abstract class AbstractEntityPersister
return expression; return expression;
} }
private List<Fetch> fetchProcessor(FetchParent fetchParent, LoaderSqlAstCreationState creationState) { private ImmutableFetchList fetchProcessor(FetchParent fetchParent, LoaderSqlAstCreationState creationState) {
final FetchableContainer fetchableContainer = fetchParent.getReferencedMappingContainer(); final FetchableContainer fetchableContainer = fetchParent.getReferencedMappingContainer();
final int size = fetchableContainer.getNumberOfFetchables(); final int size = fetchableContainer.getNumberOfFetchables();
final List<Fetch> fetches = new ArrayList<>( size ); final ImmutableFetchList.Builder fetches = new ImmutableFetchList.Builder( fetchableContainer );
for ( int i = 0; i < size; i++ ) { for ( int i = 0; i < size; i++ ) {
final Fetchable fetchable = fetchableContainer.getFetchable( i ); final Fetchable fetchable = fetchableContainer.getFetchable( i );
@ -1848,7 +1849,7 @@ public abstract class AbstractEntityPersister
} }
} }
return fetches; return fetches.build();
} }
private boolean isSelectable(FetchParent fetchParent, Fetchable fetchable) { private boolean isSelectable(FetchParent fetchParent, Fetchable fetchable) {
@ -4652,6 +4653,7 @@ public abstract class AbstractEntityPersister
final NonIdentifierAttribute[] properties = currentEntityMetamodel.getProperties(); final NonIdentifierAttribute[] properties = currentEntityMetamodel.getProperties();
AttributeMappingsMap.Builder mappingsBuilder = AttributeMappingsMap.builder(); AttributeMappingsMap.Builder mappingsBuilder = AttributeMappingsMap.builder();
int fetchableIndex = getFetchableIndexOffset();
for ( int i = 0; i < currentEntityMetamodel.getPropertySpan(); i++ ) { for ( int i = 0; i < currentEntityMetamodel.getPropertySpan(); i++ ) {
final NonIdentifierAttribute runtimeAttrDefinition = properties[i]; final NonIdentifierAttribute runtimeAttrDefinition = properties[i];
final Property bootProperty = bootEntityDescriptor.getProperty( runtimeAttrDefinition.getName() ); final Property bootProperty = bootEntityDescriptor.getProperty( runtimeAttrDefinition.getName() );
@ -4664,6 +4666,7 @@ public abstract class AbstractEntityPersister
runtimeAttrDefinition, runtimeAttrDefinition,
bootProperty, bootProperty,
stateArrayPosition++, stateArrayPosition++,
fetchableIndex++,
creationProcess creationProcess
) )
); );
@ -4701,6 +4704,7 @@ public abstract class AbstractEntityPersister
} }
final ImmutableAttributeMappingList.Builder builder = new ImmutableAttributeMappingList.Builder( attributeMappings.size() ); final ImmutableAttributeMappingList.Builder builder = new ImmutableAttributeMappingList.Builder( attributeMappings.size() );
visitSubTypeAttributeMappings( attributeMapping -> builder.add( attributeMapping ) ); visitSubTypeAttributeMappings( attributeMapping -> builder.add( attributeMapping ) );
assert superMappingType != null || builder.assertFetchableIndexes();
staticFetchableList = builder.build(); staticFetchableList = builder.build();
return true; return true;
} }
@ -4767,6 +4771,30 @@ public abstract class AbstractEntityPersister
} }
} }
private int getFetchableIndexOffset() {
if ( superMappingType != null ) {
final EntityMappingType rootEntityDescriptor = getRootEntityDescriptor();
int offset = rootEntityDescriptor.getNumberOfDeclaredAttributeMappings();
for ( EntityMappingType subMappingType : rootEntityDescriptor.getSubMappingTypes() ) {
if ( subMappingType == this ) {
break;
}
// Determining the number of attribute mappings unfortunately has to be done this way,
// because calling `subMappingType.getNumberOfDeclaredAttributeMappings()` at this point
// may produce wrong results because subMappingType might not have completed prepareMappingModel yet
final int propertySpan = subMappingType.getEntityPersister().getEntityMetamodel().getPropertySpan();
final int superPropertySpan = subMappingType.getSuperMappingType()
.getEntityPersister()
.getEntityMetamodel()
.getPropertySpan();
final int numberOfDeclaredAttributeMappings = propertySpan - superPropertySpan;
offset += numberOfDeclaredAttributeMappings;
}
return offset;
}
return 0;
}
private void prepareMappingModel(MappingModelCreationProcess creationProcess, PersistentClass bootEntityDescriptor) { private void prepareMappingModel(MappingModelCreationProcess creationProcess, PersistentClass bootEntityDescriptor) {
final EntityInstantiator instantiator = getRepresentationStrategy().getInstantiator(); final EntityInstantiator instantiator = getRepresentationStrategy().getInstantiator();
final Supplier<?> templateInstanceCreator; final Supplier<?> templateInstanceCreator;
@ -5206,6 +5234,7 @@ public abstract class AbstractEntityPersister
NonIdentifierAttribute tupleAttrDefinition, NonIdentifierAttribute tupleAttrDefinition,
Property bootProperty, Property bootProperty,
int stateArrayPosition, int stateArrayPosition,
int fetchableIndex,
MappingModelCreationProcess creationProcess) { MappingModelCreationProcess creationProcess) {
final SessionFactoryImplementor sessionFactory = creationProcess.getCreationContext().getSessionFactory(); final SessionFactoryImplementor sessionFactory = creationProcess.getCreationContext().getSessionFactory();
final JdbcServices jdbcServices = sessionFactory.getJdbcServices(); final JdbcServices jdbcServices = sessionFactory.getJdbcServices();
@ -5229,6 +5258,7 @@ public abstract class AbstractEntityPersister
attrName, attrName,
getNavigableRole().append( bootProperty.getName() ), getNavigableRole().append( bootProperty.getName() ),
stateArrayPosition, stateArrayPosition,
fetchableIndex,
bootProperty, bootProperty,
this, this,
(BasicType<?>) attrType, (BasicType<?>) attrType,
@ -5318,6 +5348,7 @@ public abstract class AbstractEntityPersister
attrName, attrName,
getNavigableRole().append( bootProperty.getName() ), getNavigableRole().append( bootProperty.getName() ),
stateArrayPosition, stateArrayPosition,
fetchableIndex,
bootProperty, bootProperty,
this, this,
(BasicType<?>) attrType, (BasicType<?>) attrType,
@ -5362,6 +5393,7 @@ public abstract class AbstractEntityPersister
baseAssociationJtd, baseAssociationJtd,
this, this,
stateArrayPosition, stateArrayPosition,
fetchableIndex,
attributeMetadataAccess, attributeMetadataAccess,
bootProperty.isLazy() ? FetchTiming.DELAYED : FetchTiming.IMMEDIATE, bootProperty.isLazy() ? FetchTiming.DELAYED : FetchTiming.IMMEDIATE,
propertyAccess, propertyAccess,
@ -5375,6 +5407,7 @@ public abstract class AbstractEntityPersister
return MappingModelCreationHelper.buildEmbeddedAttributeMapping( return MappingModelCreationHelper.buildEmbeddedAttributeMapping(
attrName, attrName,
stateArrayPosition, stateArrayPosition,
fetchableIndex,
bootProperty, bootProperty,
this, this,
(CompositeType) attrType, (CompositeType) attrType,
@ -5389,6 +5422,7 @@ public abstract class AbstractEntityPersister
return MappingModelCreationHelper.buildPluralAttributeMapping( return MappingModelCreationHelper.buildPluralAttributeMapping(
attrName, attrName,
stateArrayPosition, stateArrayPosition,
fetchableIndex,
bootProperty, bootProperty,
this, this,
propertyAccess, propertyAccess,
@ -5402,6 +5436,7 @@ public abstract class AbstractEntityPersister
attrName, attrName,
getNavigableRole().append( attrName ), getNavigableRole().append( attrName ),
stateArrayPosition, stateArrayPosition,
fetchableIndex,
bootProperty, bootProperty,
this, this,
this, this,
@ -5659,6 +5694,11 @@ public abstract class AbstractEntityPersister
return getStaticFetchableList().size(); return getStaticFetchableList().size();
} }
@Override
public int getNumberOfFetchableKeys() {
return superMappingType == null ? getNumberOfFetchables() : getRootEntityDescriptor().getNumberOfFetchables();
}
@Override @Override
public int getNumberOfKeyFetchables() { public int getNumberOfKeyFetchables() {
return 0; return 0;

View File

@ -90,6 +90,13 @@ public final class ImmutableAttributeMappingList implements AttributeMappingsLis
return new ImmutableAttributeMappingList( builderList ); return new ImmutableAttributeMappingList( builderList );
} }
public boolean assertFetchableIndexes() {
for ( int i = 0; i < builderList.size(); i++ ) {
final AttributeMapping attributeMapping = builderList.get( i );
assert i == attributeMapping.getFetchableKey();
}
return true;
}
} }
} }

View File

@ -29,7 +29,7 @@ public class AnonymousTupleBasicEntityIdentifierMapping
SqmExpressible<?> expressible, SqmExpressible<?> expressible,
JdbcMapping jdbcMapping, JdbcMapping jdbcMapping,
BasicEntityIdentifierMapping delegate) { BasicEntityIdentifierMapping delegate) {
super( delegate.getAttributeName(), selectionExpression, expressible, jdbcMapping ); super( delegate.getAttributeName(), selectionExpression, expressible, jdbcMapping, -1 );
this.delegate = delegate; this.delegate = delegate;
} }

View File

@ -47,16 +47,19 @@ public class AnonymousTupleBasicValuedModelPart implements ModelPart, MappingTyp
private final String selectionExpression; private final String selectionExpression;
private final SqmExpressible<?> expressible; private final SqmExpressible<?> expressible;
private final JdbcMapping jdbcMapping; private final JdbcMapping jdbcMapping;
private final int fetchableIndex;
public AnonymousTupleBasicValuedModelPart( public AnonymousTupleBasicValuedModelPart(
String partName, String partName,
String selectionExpression, String selectionExpression,
SqmExpressible<?> expressible, SqmExpressible<?> expressible,
JdbcMapping jdbcMapping) { JdbcMapping jdbcMapping,
int fetchableIndex) {
this.partName = partName; this.partName = partName;
this.selectionExpression = selectionExpression; this.selectionExpression = selectionExpression;
this.expressible = expressible; this.expressible = expressible;
this.jdbcMapping = jdbcMapping; this.jdbcMapping = jdbcMapping;
this.fetchableIndex = fetchableIndex;
} }
@Override @Override
@ -164,6 +167,11 @@ public class AnonymousTupleBasicValuedModelPart implements ModelPart, MappingTyp
return partName; return partName;
} }
@Override
public int getFetchableKey() {
return fetchableIndex;
}
@Override @Override
public FetchOptions getMappedFetchOptions() { public FetchOptions getMappedFetchOptions() {
return FETCH_OPTIONS; return FETCH_OPTIONS;

View File

@ -73,16 +73,19 @@ public class AnonymousTupleEmbeddableValuedModelPart implements EmbeddableValued
private final DomainType<?> domainType; private final DomainType<?> domainType;
private final String componentName; private final String componentName;
private final EmbeddableValuedModelPart existingModelPartContainer; private final EmbeddableValuedModelPart existingModelPartContainer;
private final int fetchableIndex;
public AnonymousTupleEmbeddableValuedModelPart( public AnonymousTupleEmbeddableValuedModelPart(
Map<String, ModelPart> modelParts, Map<String, ModelPart> modelParts,
DomainType<?> domainType, DomainType<?> domainType,
String componentName, String componentName,
EmbeddableValuedModelPart existingModelPartContainer) { EmbeddableValuedModelPart existingModelPartContainer,
int fetchableIndex) {
this.modelParts = modelParts; this.modelParts = modelParts;
this.domainType = domainType; this.domainType = domainType;
this.componentName = componentName; this.componentName = componentName;
this.existingModelPartContainer = existingModelPartContainer; this.existingModelPartContainer = existingModelPartContainer;
this.fetchableIndex = fetchableIndex;
} }
@Override @Override
@ -321,6 +324,11 @@ public class AnonymousTupleEmbeddableValuedModelPart implements EmbeddableValued
return getPartName(); return getPartName();
} }
@Override
public int getFetchableKey() {
return fetchableIndex;
}
@Override @Override
public FetchOptions getMappedFetchOptions() { public FetchOptions getMappedFetchOptions() {
return FETCH_OPTIONS; return FETCH_OPTIONS;

View File

@ -37,7 +37,8 @@ public class AnonymousTupleEmbeddedEntityIdentifierMapping extends AnonymousTupl
modelParts, modelParts,
domainType, domainType,
componentName, componentName,
(EmbeddableValuedModelPart) delegate (EmbeddableValuedModelPart) delegate,
-1
); );
this.delegate = delegate; this.delegate = delegate;
} }

View File

@ -82,12 +82,14 @@ public class AnonymousTupleEntityValuedModelPart
private final String componentName; private final String componentName;
private final EntityValuedModelPart delegate; private final EntityValuedModelPart delegate;
private final Set<String> targetKeyPropertyNames; private final Set<String> targetKeyPropertyNames;
private final int fetchableIndex;
public AnonymousTupleEntityValuedModelPart( public AnonymousTupleEntityValuedModelPart(
EntityIdentifierMapping identifierMapping, EntityIdentifierMapping identifierMapping,
DomainType<?> domainType, DomainType<?> domainType,
String componentName, String componentName,
EntityValuedModelPart delegate) { EntityValuedModelPart delegate,
int fetchableIndex) {
this.identifierMapping = identifierMapping; this.identifierMapping = identifierMapping;
this.domainType = domainType; this.domainType = domainType;
this.componentName = componentName; this.componentName = componentName;
@ -103,6 +105,7 @@ public class AnonymousTupleEntityValuedModelPart
persister.getFactory() persister.getFactory()
); );
this.targetKeyPropertyNames = targetKeyPropertyNames; this.targetKeyPropertyNames = targetKeyPropertyNames;
this.fetchableIndex = fetchableIndex;
} }
public ModelPart getForeignKeyPart() { public ModelPart getForeignKeyPart() {

View File

@ -38,7 +38,8 @@ public class AnonymousTupleNonAggregatedEntityIdentifierMapping extends Anonymou
modelParts, modelParts,
domainType, domainType,
componentName, componentName,
delegate delegate,
-1
); );
this.delegate = delegate; this.delegate = delegate;
} }

View File

@ -98,7 +98,8 @@ public class AnonymousTupleTableGroupProducer implements TableGroupProducer, Map
partName, partName,
partName, partName,
tableGroup == null ? null : getModelPart( tableGroup ), tableGroup == null ? null : getModelPart( tableGroup ),
compatibleTableExpressions compatibleTableExpressions,
modelParts.size()
); );
} }
else { else {
@ -108,7 +109,8 @@ public class AnonymousTupleTableGroupProducer implements TableGroupProducer, Map
selectableNode.getExpressible(), selectableNode.getExpressible(),
sqlSelection.getExpressionType() sqlSelection.getExpressionType()
.getJdbcMappings() .getJdbcMappings()
.get( 0 ) .get( 0 ),
modelParts.size()
); );
} }
modelParts.put( partName, modelPart ); modelParts.put( partName, modelPart );
@ -136,7 +138,8 @@ public class AnonymousTupleTableGroupProducer implements TableGroupProducer, Map
String selectionExpression, String selectionExpression,
String partName, String partName,
ModelPart existingModelPart, ModelPart existingModelPart,
Set<String> compatibleTableExpressions) { Set<String> compatibleTableExpressions,
int fetchableIndex) {
if ( domainType instanceof EntityDomainType<?> ) { if ( domainType instanceof EntityDomainType<?> ) {
final EntityValuedModelPart existingModelPartContainer = (EntityValuedModelPart) existingModelPart; final EntityValuedModelPart existingModelPartContainer = (EntityValuedModelPart) existingModelPart;
final EntityIdentifierMapping identifierMapping = existingModelPartContainer.getEntityMappingType() final EntityIdentifierMapping identifierMapping = existingModelPartContainer.getEntityMappingType()
@ -149,6 +152,7 @@ public class AnonymousTupleTableGroupProducer implements TableGroupProducer, Map
final Set<Attribute<?, ?>> attributes = (Set<Attribute<?, ?>>) ( (ManagedDomainType<?>) ( (EntityDomainType<?>) domainType ).getIdentifierDescriptor().getSqmPathType() ).getAttributes(); final Set<Attribute<?, ?>> attributes = (Set<Attribute<?, ?>>) ( (ManagedDomainType<?>) ( (EntityDomainType<?>) domainType ).getIdentifierDescriptor().getSqmPathType() ).getAttributes();
final Map<String, ModelPart> modelParts = CollectionHelper.linkedMapOfSize( attributes.size() ); final Map<String, ModelPart> modelParts = CollectionHelper.linkedMapOfSize( attributes.size() );
final EmbeddableValuedModelPart modelPartContainer = (EmbeddableValuedModelPart) identifierMapping; final EmbeddableValuedModelPart modelPartContainer = (EmbeddableValuedModelPart) identifierMapping;
int index = 0;
for ( Attribute<?, ?> attribute : attributes ) { for ( Attribute<?, ?> attribute : attributes ) {
if ( !( attribute instanceof SingularPersistentAttribute<?, ?> ) ) { if ( !( attribute instanceof SingularPersistentAttribute<?, ?> ) ) {
throw new IllegalArgumentException( "Only embeddables without collections are supported!" ); throw new IllegalArgumentException( "Only embeddables without collections are supported!" );
@ -162,7 +166,8 @@ public class AnonymousTupleTableGroupProducer implements TableGroupProducer, Map
selectionExpression + "_" + attributeName + "_" + attribute.getName(), selectionExpression + "_" + attributeName + "_" + attribute.getName(),
attribute.getName(), attribute.getName(),
modelPartContainer.findSubPart( attribute.getName(), null ), modelPartContainer.findSubPart( attribute.getName(), null ),
compatibleTableExpressions compatibleTableExpressions,
index++
); );
modelParts.put( modelPart.getPartName(), modelPart ); modelParts.put( modelPart.getPartName(), modelPart );
} }
@ -190,6 +195,7 @@ public class AnonymousTupleTableGroupProducer implements TableGroupProducer, Map
final Set<Attribute<?, ?>> attributes = (Set<Attribute<?, ?>>) ( (ManagedDomainType<?>) ( (EntityDomainType<?>) domainType ).getIdentifierDescriptor().getSqmPathType() ).getAttributes(); final Set<Attribute<?, ?>> attributes = (Set<Attribute<?, ?>>) ( (ManagedDomainType<?>) ( (EntityDomainType<?>) domainType ).getIdentifierDescriptor().getSqmPathType() ).getAttributes();
final Map<String, ModelPart> modelParts = CollectionHelper.linkedMapOfSize( attributes.size() ); final Map<String, ModelPart> modelParts = CollectionHelper.linkedMapOfSize( attributes.size() );
final EmbeddableValuedModelPart modelPartContainer = (EmbeddableValuedModelPart) identifierMapping; final EmbeddableValuedModelPart modelPartContainer = (EmbeddableValuedModelPart) identifierMapping;
int index = 0;
for ( Attribute<?, ?> attribute : attributes ) { for ( Attribute<?, ?> attribute : attributes ) {
if ( !( attribute instanceof SingularPersistentAttribute<?, ?> ) ) { if ( !( attribute instanceof SingularPersistentAttribute<?, ?> ) ) {
throw new IllegalArgumentException( "Only embeddables without collections are supported!" ); throw new IllegalArgumentException( "Only embeddables without collections are supported!" );
@ -203,7 +209,8 @@ public class AnonymousTupleTableGroupProducer implements TableGroupProducer, Map
selectionExpression + "_" + attribute.getName(), selectionExpression + "_" + attribute.getName(),
attribute.getName(), attribute.getName(),
modelPartContainer.findSubPart( attribute.getName(), null ), modelPartContainer.findSubPart( attribute.getName(), null ),
compatibleTableExpressions compatibleTableExpressions,
index++
); );
modelParts.put( modelPart.getPartName(), modelPart ); modelParts.put( modelPart.getPartName(), modelPart );
} }
@ -222,7 +229,8 @@ public class AnonymousTupleTableGroupProducer implements TableGroupProducer, Map
newIdentifierMapping, newIdentifierMapping,
domainType, domainType,
selectionExpression, selectionExpression,
existingModelPartContainer existingModelPartContainer,
fetchableIndex
); );
} }
else if ( domainType instanceof ManagedDomainType<?> ) { else if ( domainType instanceof ManagedDomainType<?> ) {
@ -230,6 +238,7 @@ public class AnonymousTupleTableGroupProducer implements TableGroupProducer, Map
final Set<Attribute<?, ?>> attributes = (Set<Attribute<?, ?>>) ( (ManagedDomainType<?>) domainType ).getAttributes(); final Set<Attribute<?, ?>> attributes = (Set<Attribute<?, ?>>) ( (ManagedDomainType<?>) domainType ).getAttributes();
final Map<String, ModelPart> modelParts = CollectionHelper.linkedMapOfSize( attributes.size() ); final Map<String, ModelPart> modelParts = CollectionHelper.linkedMapOfSize( attributes.size() );
final EmbeddableValuedModelPart modelPartContainer = (EmbeddableValuedModelPart) existingModelPart; final EmbeddableValuedModelPart modelPartContainer = (EmbeddableValuedModelPart) existingModelPart;
int index = 0;
for ( Attribute<?, ?> attribute : attributes ) { for ( Attribute<?, ?> attribute : attributes ) {
if ( !( attribute instanceof SingularPersistentAttribute<?, ?> ) ) { if ( !( attribute instanceof SingularPersistentAttribute<?, ?> ) ) {
throw new IllegalArgumentException( "Only embeddables without collections are supported" ); throw new IllegalArgumentException( "Only embeddables without collections are supported" );
@ -243,11 +252,12 @@ public class AnonymousTupleTableGroupProducer implements TableGroupProducer, Map
selectionExpression + "_" + attribute.getName(), selectionExpression + "_" + attribute.getName(),
attribute.getName(), attribute.getName(),
modelPartContainer.findSubPart( attribute.getName(), null ), modelPartContainer.findSubPart( attribute.getName(), null ),
compatibleTableExpressions compatibleTableExpressions,
index++
); );
modelParts.put( modelPart.getPartName(), modelPart ); modelParts.put( modelPart.getPartName(), modelPart );
} }
return new AnonymousTupleEmbeddableValuedModelPart( modelParts, domainType, selectionExpression, modelPartContainer ); return new AnonymousTupleEmbeddableValuedModelPart( modelParts, domainType, selectionExpression, modelPartContainer, fetchableIndex );
} }
else { else {
return new AnonymousTupleBasicValuedModelPart( return new AnonymousTupleBasicValuedModelPart(
@ -257,7 +267,8 @@ public class AnonymousTupleTableGroupProducer implements TableGroupProducer, Map
sqlSelections.get( selectionIndex ) sqlSelections.get( selectionIndex )
.getExpressionType() .getExpressionType()
.getJdbcMappings() .getJdbcMappings()
.get( 0 ) .get( 0 ),
fetchableIndex
); );
} }
} }

View File

@ -59,7 +59,8 @@ public class CteTupleTableGroupProducer extends AnonymousTupleTableGroupProducer
attributeName, attributeName,
attributeName, attributeName,
basicType, basicType,
basicType basicType,
-1
); );
} }
return null; return null;

View File

@ -8,7 +8,6 @@ package org.hibernate.query.results;
import java.util.AbstractMap; import java.util.AbstractMap;
import java.util.HashMap; import java.util.HashMap;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.function.Consumer; import java.util.function.Consumer;
import java.util.function.Function; import java.util.function.Function;
@ -17,7 +16,6 @@ import org.hibernate.Internal;
import org.hibernate.LockMode; import org.hibernate.LockMode;
import org.hibernate.engine.FetchTiming; import org.hibernate.engine.FetchTiming;
import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.internal.util.collections.CollectionHelper;
import org.hibernate.internal.util.collections.Stack; import org.hibernate.internal.util.collections.Stack;
import org.hibernate.internal.util.collections.StandardStack; import org.hibernate.internal.util.collections.StandardStack;
import org.hibernate.metamodel.mapping.Association; import org.hibernate.metamodel.mapping.Association;
@ -51,6 +49,8 @@ import org.hibernate.sql.results.graph.Fetch;
import org.hibernate.sql.results.graph.FetchParent; import org.hibernate.sql.results.graph.FetchParent;
import org.hibernate.sql.results.graph.Fetchable; import org.hibernate.sql.results.graph.Fetchable;
import org.hibernate.sql.results.graph.FetchableContainer; import org.hibernate.sql.results.graph.FetchableContainer;
import org.hibernate.sql.results.graph.entity.EntityResultGraphNode;
import org.hibernate.sql.results.graph.internal.ImmutableFetchList;
import org.hibernate.sql.results.jdbc.spi.JdbcValuesMetadata; import org.hibernate.sql.results.jdbc.spi.JdbcValuesMetadata;
import org.hibernate.type.descriptor.java.JavaType; import org.hibernate.type.descriptor.java.JavaType;
import org.hibernate.type.spi.TypeConfiguration; import org.hibernate.type.spi.TypeConfiguration;
@ -126,9 +126,8 @@ public class DomainResultCreationStateImpl
return jdbcResultsMetadata; return jdbcResultsMetadata;
} }
public NavigablePath getCurrentRelativePath() { public Map.Entry<String, NavigablePath> getCurrentRelativePath() {
final Map.Entry<String, NavigablePath> entry = relativePathStack.getCurrent(); return relativePathStack.getCurrent();
return entry == null ? null : entry.getValue();
} }
public void pushExplicitFetchMementoResolver(Function<String, FetchBuilder> resolver) { public void pushExplicitFetchMementoResolver(Function<String, FetchBuilder> resolver) {
@ -332,26 +331,106 @@ public class DomainResultCreationStateImpl
} }
@Override @Override
public List<Fetch> visitNestedFetches(FetchParent fetchParent) { public ImmutableFetchList visitNestedFetches(FetchParent fetchParent) {
final FetchParent oldNestingFetchParent = this.nestingFetchParent; final FetchParent oldNestingFetchParent = this.nestingFetchParent;
this.nestingFetchParent = fetchParent; this.nestingFetchParent = fetchParent;
final List<Fetch> fetches = visitFetches( fetchParent ); final ImmutableFetchList fetches = visitFetches( fetchParent );
this.nestingFetchParent = oldNestingFetchParent; this.nestingFetchParent = oldNestingFetchParent;
return fetches; return fetches;
} }
@Override @Override
public List<Fetch> visitFetches(FetchParent fetchParent) { public Fetch visitIdentifierFetch(EntityResultGraphNode fetchParent) {
final EntityValuedModelPart entityValuedFetchable = fetchParent.getEntityValuedModelPart();
final EntityIdentifierMapping identifierMapping = entityValuedFetchable.getEntityMappingType().getIdentifierMapping();
final String identifierAttributeName = attributeName( identifierMapping );
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 fetchable = (Fetchable) identifierMapping;
final FetchBuilder explicitFetchBuilder = fetchBuilderResolverStack
.getCurrent()
.apply( fullPath );
DynamicFetchBuilderLegacy fetchBuilderLegacy;
if ( explicitFetchBuilder == null ) {
fetchBuilderLegacy = legacyFetchResolver.resolve(
fromClauseAccess.findTableGroup( fetchParent.getNavigablePath() )
.getPrimaryTableReference()
.getIdentificationVariable(),
identifierAttributeName
);
}
else {
fetchBuilderLegacy = null;
}
final EntityIdentifierNavigablePath fetchPath = new EntityIdentifierNavigablePath(
fetchParent.getNavigablePath(),
identifierAttributeName
);
final boolean processingKeyFetches = this.processingKeyFetches;
this.processingKeyFetches = true;
if ( identifierMapping instanceof CompositeIdentifierMapping ) {
relativePathStack.push( new AbstractMap.SimpleEntry<>( fullPath, fetchPath ) );
}
try {
final FetchBuilder fetchBuilder;
if ( explicitFetchBuilder != null ) {
fetchBuilder = explicitFetchBuilder;
}
else {
if ( fetchBuilderLegacy == null ) {
fetchBuilder = Builders.implicitFetchBuilder( fetchPath, fetchable, this );
}
else {
fetchBuilder = fetchBuilderLegacy;
}
}
return fetchBuilder.buildFetch(
fetchParent,
fetchPath,
jdbcResultsMetadata,
(s, s2) -> {
throw new UnsupportedOperationException();
},
this
);
}
finally {
this.processingKeyFetches = processingKeyFetches;
if ( identifierMapping instanceof CompositeIdentifierMapping ) {
this.relativePathStack.pop();
}
}
}
@Override
public ImmutableFetchList visitFetches(FetchParent fetchParent) {
final FetchableContainer fetchableContainer = fetchParent.getReferencedMappingContainer(); final FetchableContainer fetchableContainer = fetchParent.getReferencedMappingContainer();
final ImmutableFetchList.Builder fetches = new ImmutableFetchList.Builder( fetchableContainer );
final Consumer<Fetchable> fetchableConsumer = createFetchableConsumer( fetchParent, fetches );
fetchableContainer.visitKeyFetchables( fetchableConsumer, null );
fetchableContainer.visitFetchables( fetchableConsumer, null );
return fetches.build();
}
final List<Fetch> fetches = CollectionHelper.arrayList( fetchableContainer.getNumberOfFetchables() ); private Consumer<Fetchable> createFetchableConsumer(FetchParent fetchParent, ImmutableFetchList.Builder fetches) {
return fetchable -> {
final Consumer<Fetchable> fetchableConsumer = fetchable -> {
final String fetchableName = fetchable.getFetchableName(); final String fetchableName = fetchable.getFetchableName();
Map.Entry<String, NavigablePath> currentEntry; Map.Entry<String, NavigablePath> currentEntry;
if ( relativePathStack.isEmpty() ) { if ( relativePathStack.isEmpty() ) {
currentEntry = new AbstractMap.SimpleEntry<>( currentEntry = new AbstractMap.SimpleEntry<>(
getRelativePath( "", fetchable, fetchableContainer ), getRelativePath( "", fetchable ),
new NavigablePath( fetchableName ) new NavigablePath( fetchableName )
); );
} }
@ -359,7 +438,7 @@ public class DomainResultCreationStateImpl
final Map.Entry<String, NavigablePath> oldEntry = relativePathStack.getCurrent(); final Map.Entry<String, NavigablePath> oldEntry = relativePathStack.getCurrent();
final String key = oldEntry.getKey(); final String key = oldEntry.getKey();
currentEntry = new AbstractMap.SimpleEntry<>( currentEntry = new AbstractMap.SimpleEntry<>(
getRelativePath( key, fetchable, fetchableContainer ), getRelativePath( key, fetchable ),
oldEntry.getValue().append( fetchableName ) oldEntry.getValue().append( fetchableName )
); );
} }
@ -384,8 +463,9 @@ public class DomainResultCreationStateImpl
final Association association = (Association) fetchable; final Association association = (Association) fetchable;
final ForeignKeyDescriptor foreignKeyDescriptor = association.getForeignKeyDescriptor(); final ForeignKeyDescriptor foreignKeyDescriptor = association.getForeignKeyDescriptor();
final String partName = attributeName( foreignKeyDescriptor.getSide( association.getSideNature().inverse() ) final String partName = attributeName(
.getModelPart()); foreignKeyDescriptor.getSide( association.getSideNature().inverse() ).getModelPart()
);
// If there are no fetch builders for this association, we only want to fetch the FK // If there are no fetch builders for this association, we only want to fetch the FK
if ( explicitFetchBuilder == null && fetchBuilderLegacy == null && partName != null ) { if ( explicitFetchBuilder == null && fetchBuilderLegacy == null && partName != null ) {
@ -438,65 +518,9 @@ public class DomainResultCreationStateImpl
} }
}; };
boolean previous = this.processingKeyFetches;
this.processingKeyFetches = true;
if ( fetchableContainer instanceof EntityValuedModelPart ) {
final EntityValuedModelPart entityValuedFetchable = (EntityValuedModelPart) fetchableContainer;
final EntityIdentifierMapping identifierMapping = entityValuedFetchable.getEntityMappingType().getIdentifierMapping();
final boolean idClass = identifierMapping instanceof NonAggregatedIdentifierMapping;
final String identifierAttributeName = attributeName( identifierMapping );
if ( idClass ) {
final Map.Entry<String, NavigablePath> oldEntry = relativePathStack.getCurrent();
relativePathStack.push(
new AbstractMap.SimpleEntry<>(
oldEntry == null ? "" : oldEntry.getKey(),
new EntityIdentifierNavigablePath(
oldEntry == null ? fetchParent.getNavigablePath() : oldEntry.getValue(),
identifierAttributeName
)
)
);
}
else if ( identifierMapping instanceof CompositeIdentifierMapping ) {
final Map.Entry<String, NavigablePath> oldEntry = relativePathStack.getCurrent();
relativePathStack.push(
new AbstractMap.SimpleEntry<>(
oldEntry == null ?
identifierAttributeName :
oldEntry.getKey() + "." + identifierAttributeName,
new EntityIdentifierNavigablePath(
oldEntry == null ? fetchParent.getNavigablePath() : oldEntry.getValue(),
identifierAttributeName
)
)
);
} }
try { private String getRelativePath(String oldEntry, Fetchable fetchable) {
if ( identifierMapping instanceof FetchableContainer ) {
// essentially means the entity has a composite id - ask the embeddable to visit its fetchables
( (FetchableContainer) identifierMapping ).visitFetchables( fetchableConsumer, null );
}
else {
fetchableConsumer.accept( (Fetchable) identifierMapping );
}
}
finally {
this.processingKeyFetches = previous;
if ( idClass ) {
this.relativePathStack.pop();
}
}
}
fetchableContainer.visitKeyFetchables( fetchableConsumer, null );
fetchableContainer.visitFetchables( fetchableConsumer, null );
return fetches;
}
private String getRelativePath(String oldEntry, Fetchable fetchable, FetchableContainer fetchableContainer) {
if ( fetchable instanceof AttributeMapping || fetchable instanceof SingleAttributeIdentifierMapping || fetchable instanceof BasicValuedCollectionPart ) { if ( fetchable instanceof AttributeMapping || fetchable instanceof SingleAttributeIdentifierMapping || fetchable instanceof BasicValuedCollectionPart ) {
if ( !oldEntry.equals( "" ) ) { if ( !oldEntry.equals( "" ) ) {
return oldEntry + '.' + fetchable.getFetchableName(); return oldEntry + '.' + fetchable.getFetchableName();

View File

@ -36,6 +36,7 @@ import org.hibernate.sql.results.graph.basic.BasicFetch;
import org.hibernate.sql.results.graph.basic.BasicResult; import org.hibernate.sql.results.graph.basic.BasicResult;
import org.hibernate.sql.results.graph.embeddable.EmbeddableResultGraphNode; import org.hibernate.sql.results.graph.embeddable.EmbeddableResultGraphNode;
import org.hibernate.sql.results.graph.entity.EntityResult; import org.hibernate.sql.results.graph.entity.EntityResult;
import org.hibernate.sql.results.graph.internal.ImmutableFetchList;
import org.hibernate.sql.results.jdbc.spi.JdbcValuesMapping; import org.hibernate.sql.results.jdbc.spi.JdbcValuesMapping;
import org.hibernate.sql.results.jdbc.spi.JdbcValuesMappingProducer; import org.hibernate.sql.results.jdbc.spi.JdbcValuesMappingProducer;
import org.hibernate.sql.results.jdbc.spi.JdbcValuesMetadata; import org.hibernate.sql.results.jdbc.spi.JdbcValuesMetadata;
@ -248,7 +249,7 @@ public class ResultSetMappingImpl implements ResultSetMapping {
// otherwise we assume that even if there are duplicate aliases, the values are equivalent. // otherwise we assume that even if there are duplicate aliases, the values are equivalent.
// If we don't do that, there is no way to fetch joined inheritance entities // If we don't do that, there is no way to fetch joined inheritance entities
if ( polymorphic && ( legacyFetchBuilders == null || legacyFetchBuilders.isEmpty() ) if ( polymorphic && ( legacyFetchBuilders == null || legacyFetchBuilders.isEmpty() )
&& !hasJoinFetches( entityResult.getFetches() ) ) { && !entityResult.hasJoinFetches() ) {
final Set<String> aliases = new TreeSet<>( String.CASE_INSENSITIVE_ORDER ); final Set<String> aliases = new TreeSet<>( String.CASE_INSENSITIVE_ORDER );
final AbstractEntityPersister entityPersister = (AbstractEntityPersister) entityResult.getReferencedMappingContainer() final AbstractEntityPersister entityPersister = (AbstractEntityPersister) entityResult.getReferencedMappingContainer()
.getEntityPersister(); .getEntityPersister();
@ -305,25 +306,6 @@ public class ResultSetMappingImpl implements ResultSetMapping {
} }
} }
private static boolean hasJoinFetches(List<Fetch> fetches) {
for ( int i = 0; i < fetches.size(); i++ ) {
final Fetch fetch = fetches.get( i );
if ( fetch instanceof BasicFetch<?> || fetch.getTiming() == FetchTiming.DELAYED ) {
// That's fine
}
else if ( fetch instanceof EmbeddableResultGraphNode ) {
// Check all these fetches as well
if ( hasJoinFetches( ( (EmbeddableResultGraphNode) fetch ).getFetches() ) ) {
return true;
}
}
else {
return true;
}
}
return false;
}
private DomainResult<?> makeImplicitDomainResult( private DomainResult<?> makeImplicitDomainResult(
int valuesArrayPosition, int valuesArrayPosition,
Consumer<SqlSelection> sqlSelectionConsumer, Consumer<SqlSelection> sqlSelectionConsumer,

View File

@ -6,19 +6,11 @@
*/ */
package org.hibernate.query.results.complete; package org.hibernate.query.results.complete;
import java.util.Collections;
import java.util.List;
import java.util.function.Function; import java.util.function.Function;
import org.hibernate.LockMode; import org.hibernate.LockMode;
import org.hibernate.engine.FetchTiming;
import org.hibernate.internal.util.MutableObject;
import org.hibernate.metamodel.mapping.EntityIdentifierMapping;
import org.hibernate.metamodel.mapping.EntityValuedModelPart; import org.hibernate.metamodel.mapping.EntityValuedModelPart;
import org.hibernate.metamodel.mapping.internal.SingleAttributeIdentifierMapping;
import org.hibernate.spi.EntityIdentifierNavigablePath;
import org.hibernate.spi.NavigablePath; import org.hibernate.spi.NavigablePath;
import org.hibernate.query.results.ResultsHelper;
import org.hibernate.sql.ast.spi.SqlAstCreationState; import org.hibernate.sql.ast.spi.SqlAstCreationState;
import org.hibernate.sql.results.graph.AssemblerCreationState; import org.hibernate.sql.results.graph.AssemblerCreationState;
import org.hibernate.sql.results.graph.DomainResultAssembler; import org.hibernate.sql.results.graph.DomainResultAssembler;
@ -28,10 +20,10 @@ import org.hibernate.sql.results.graph.FetchParentAccess;
import org.hibernate.sql.results.graph.Fetchable; import org.hibernate.sql.results.graph.Fetchable;
import org.hibernate.sql.results.graph.Initializer; import org.hibernate.sql.results.graph.Initializer;
import org.hibernate.sql.results.graph.basic.BasicFetch; import org.hibernate.sql.results.graph.basic.BasicFetch;
import org.hibernate.sql.results.graph.entity.EntityInitializer;
import org.hibernate.sql.results.graph.entity.EntityResult; import org.hibernate.sql.results.graph.entity.EntityResult;
import org.hibernate.sql.results.graph.entity.internal.EntityAssembler; import org.hibernate.sql.results.graph.entity.internal.EntityAssembler;
import org.hibernate.sql.results.graph.entity.internal.EntityResultInitializer; import org.hibernate.sql.results.graph.entity.internal.EntityResultInitializer;
import org.hibernate.sql.results.graph.internal.ImmutableFetchList;
/** /**
* @author Steve Ebersole * @author Steve Ebersole
@ -42,12 +34,13 @@ public class EntityResultImpl implements EntityResult {
private final Fetch identifierFetch; private final Fetch identifierFetch;
private final BasicFetch<?> discriminatorFetch; private final BasicFetch<?> discriminatorFetch;
private final List<Fetch> fetches; private final ImmutableFetchList fetches;
private final boolean hasJoinFetches;
private final boolean containsCollectionFetches;
private final String resultAlias; private final String resultAlias;
private final LockMode lockMode; private final LockMode lockMode;
@SuppressWarnings( { "PointlessNullCheck" } )
public EntityResultImpl( public EntityResultImpl(
NavigablePath navigablePath, NavigablePath navigablePath,
EntityValuedModelPart entityValuedModelPart, EntityValuedModelPart entityValuedModelPart,
@ -78,49 +71,12 @@ public class EntityResultImpl implements EntityResult {
} }
); );
this.identifierFetch = creationState.visitIdentifierFetch( this );
this.discriminatorFetch = discriminatorFetchBuilder.apply( this ); this.discriminatorFetch = discriminatorFetchBuilder.apply( this );
final List<Fetch> localFetches = creationState.visitFetches( this ); this.fetches = creationState.visitFetches( this );
this.hasJoinFetches = fetches.hasJoinFetches();
final EntityIdentifierMapping identifierMapping = entityValuedModelPart this.containsCollectionFetches = fetches.containsCollectionFetches();
.getEntityMappingType()
.getIdentifierMapping();
final String idAttributeName = identifierMapping instanceof SingleAttributeIdentifierMapping
? ( (SingleAttributeIdentifierMapping) identifierMapping ).getAttributeName()
: null;
final MutableObject<Fetch> idFetchRef = new MutableObject<>();
for ( int i = 0; i < localFetches.size(); i++ ) {
final Fetch fetch = localFetches.get( i );
final String fetchLocalName = fetch.getNavigablePath().getLocalName();
if ( fetchLocalName.equals( EntityIdentifierMapping.ROLE_LOCAL_NAME )
|| ( idAttributeName != null && fetchLocalName.equals( idAttributeName ) ) ) {
// we found the id fetch
idFetchRef.set( fetch );
localFetches.remove( i );
break;
}
}
this.fetches = Collections.unmodifiableList( localFetches );
if ( idFetchRef.isNotSet() ) {
identifierFetch = ( (Fetchable) identifierMapping ).generateFetch(
this,
new EntityIdentifierNavigablePath(
navigablePath,
ResultsHelper.attributeName( identifierMapping )
),
FetchTiming.IMMEDIATE,
true,
null,
creationState
);
}
else {
this.identifierFetch = idFetchRef.get();
}
} }
@Override @Override
@ -144,20 +100,23 @@ public class EntityResultImpl implements EntityResult {
} }
@Override @Override
public List<Fetch> getFetches() { public ImmutableFetchList getFetches() {
return fetches; return fetches;
} }
@Override @Override
public Fetch findFetch(Fetchable fetchable) { public Fetch findFetch(Fetchable fetchable) {
final String name = fetchable.getFetchableName(); return fetches.get( fetchable );
for ( int i = 0; i < fetches.size(); i++ ) {
final Fetch fetch = fetches.get( i );
if ( fetch.getFetchedMapping().getFetchableName().equals( name ) ) {
return fetch;
} }
@Override
public boolean hasJoinFetches() {
return hasJoinFetches;
} }
return null;
@Override
public boolean containsCollectionFetches() {
return containsCollectionFetches;
} }
@Override @Override

View File

@ -199,13 +199,13 @@ public class DynamicFetchBuilderLegacy implements DynamicFetchBuilder, NativeQue
} }
} }
try { try {
final NavigablePath currentRelativePath = creationState.getCurrentRelativePath(); final Map.Entry<String, NavigablePath> currentRelativePath = creationState.getCurrentRelativePath();
final String prefix; final String prefix;
if ( currentRelativePath == null ) { if ( currentRelativePath == null ) {
prefix = ""; prefix = "";
} }
else { else {
prefix = currentRelativePath.getFullPath() prefix = currentRelativePath.getKey()
.replace( ELEMENT_PREFIX, "" ) .replace( ELEMENT_PREFIX, "" )
.replace( INDEX_PREFIX, "" ) + "."; .replace( INDEX_PREFIX, "" ) + ".";
} }

View File

@ -14,13 +14,11 @@ import org.hibernate.engine.FetchTiming;
import org.hibernate.metamodel.mapping.BasicValuedMapping; import org.hibernate.metamodel.mapping.BasicValuedMapping;
import org.hibernate.metamodel.mapping.PluralAttributeMapping; import org.hibernate.metamodel.mapping.PluralAttributeMapping;
import org.hibernate.metamodel.mapping.SelectableConsumer; import org.hibernate.metamodel.mapping.SelectableConsumer;
import org.hibernate.metamodel.mapping.internal.EmbeddedAttributeMapping;
import org.hibernate.metamodel.mapping.internal.ToOneAttributeMapping; import org.hibernate.metamodel.mapping.internal.ToOneAttributeMapping;
import org.hibernate.query.NativeQuery; import org.hibernate.query.NativeQuery;
import org.hibernate.spi.NavigablePath; import org.hibernate.spi.NavigablePath;
import org.hibernate.query.results.DomainResultCreationStateImpl; import org.hibernate.query.results.DomainResultCreationStateImpl;
import org.hibernate.query.results.ResultsHelper; import org.hibernate.query.results.ResultsHelper;
import org.hibernate.query.results.ResultSetMappingSqlSelection;
import org.hibernate.sql.ast.spi.SqlExpressionResolver; import org.hibernate.sql.ast.spi.SqlExpressionResolver;
import org.hibernate.sql.ast.tree.from.TableGroup; import org.hibernate.sql.ast.tree.from.TableGroup;
import org.hibernate.sql.ast.tree.from.TableReference; import org.hibernate.sql.ast.tree.from.TableReference;
@ -28,6 +26,7 @@ import org.hibernate.sql.results.graph.DomainResultCreationState;
import org.hibernate.sql.results.graph.Fetch; import org.hibernate.sql.results.graph.Fetch;
import org.hibernate.sql.results.graph.FetchParent; import org.hibernate.sql.results.graph.FetchParent;
import org.hibernate.sql.results.graph.Fetchable; import org.hibernate.sql.results.graph.Fetchable;
import org.hibernate.sql.results.graph.embeddable.EmbeddableValuedFetchable;
import org.hibernate.sql.results.jdbc.spi.JdbcValuesMetadata; 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.createColumnReferenceKey;
@ -114,7 +113,7 @@ public class DynamicFetchBuilderStandard
creationStateImpl creationStateImpl
); );
} }
else if ( attributeMapping instanceof EmbeddedAttributeMapping ) { else if ( attributeMapping instanceof EmbeddableValuedFetchable ) {
attributeMapping.forEachSelectable( selectableConsumer ); attributeMapping.forEachSelectable( selectableConsumer );
return parent.generateFetchableFetch( return parent.generateFetchableFetch(
attributeMapping, attributeMapping,

View File

@ -9,6 +9,7 @@ package org.hibernate.query.results.dynamic;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.function.BiFunction; import java.util.function.BiFunction;
import java.util.function.Function; import java.util.function.Function;
@ -279,13 +280,13 @@ public class DynamicResultBuilderEntityStandard
} }
try { try {
final NavigablePath currentRelativePath = creationState.getCurrentRelativePath(); final Map.Entry<String, NavigablePath> currentRelativePath = creationState.getCurrentRelativePath();
final String prefix; final String prefix;
if ( currentRelativePath == null ) { if ( currentRelativePath == null ) {
prefix = ""; prefix = "";
} }
else { else {
prefix = currentRelativePath.getFullPath() prefix = currentRelativePath.getKey()
.replace( ELEMENT_PREFIX, "" ) .replace( ELEMENT_PREFIX, "" )
.replace( INDEX_PREFIX, "" ) + "."; .replace( INDEX_PREFIX, "" ) + ".";
} }

View File

@ -51,13 +51,13 @@ public class ImplicitFetchBuilderEmbeddable implements ImplicitFetchBuilder {
this.fetchPath = fetchPath; this.fetchPath = fetchPath;
this.fetchable = fetchable; this.fetchable = fetchable;
final DomainResultCreationStateImpl creationStateImpl = impl( creationState ); final DomainResultCreationStateImpl creationStateImpl = impl( creationState );
final NavigablePath relativePath = creationStateImpl.getCurrentRelativePath(); final Map.Entry<String, NavigablePath> relativePath = creationStateImpl.getCurrentRelativePath();
final Function<String, FetchBuilder> fetchBuilderResolver = creationStateImpl.getCurrentExplicitFetchMementoResolver(); final Function<String, FetchBuilder> fetchBuilderResolver = creationStateImpl.getCurrentExplicitFetchMementoResolver();
final int size = fetchable.getNumberOfFetchables(); final int size = fetchable.getNumberOfFetchables();
final Map<NavigablePath, FetchBuilder> fetchBuilders = CollectionHelper.linkedMapOfSize( size ); final Map<NavigablePath, FetchBuilder> fetchBuilders = CollectionHelper.linkedMapOfSize( size );
for ( int i = 0; i < size; i++ ) { for ( int i = 0; i < size; i++ ) {
final Fetchable subFetchable = fetchable.getFetchable( i ); final Fetchable subFetchable = fetchable.getFetchable( i );
final NavigablePath subFetchPath = relativePath.append( subFetchable.getFetchableName() ); final NavigablePath subFetchPath = relativePath.getValue().append( subFetchable.getFetchableName() );
final FetchBuilder explicitFetchBuilder = fetchBuilderResolver.apply( subFetchPath.getFullPath() ); final FetchBuilder explicitFetchBuilder = fetchBuilderResolver.apply( subFetchPath.getFullPath() );
if ( explicitFetchBuilder == null ) { if ( explicitFetchBuilder == null ) {
fetchBuilders.put( fetchBuilders.put(

View File

@ -48,25 +48,25 @@ public class ImplicitFetchBuilderEntity implements ImplicitFetchBuilder {
this.fetchPath = fetchPath; this.fetchPath = fetchPath;
this.fetchable = fetchable; this.fetchable = fetchable;
final DomainResultCreationStateImpl creationStateImpl = impl( creationState ); final DomainResultCreationStateImpl creationStateImpl = impl( creationState );
final NavigablePath relativePath = creationStateImpl.getCurrentRelativePath(); final Map.Entry<String, NavigablePath> relativePath = creationStateImpl.getCurrentRelativePath();
final Function<String, FetchBuilder> fetchBuilderResolver = creationStateImpl.getCurrentExplicitFetchMementoResolver(); final Function<String, FetchBuilder> fetchBuilderResolver = creationStateImpl.getCurrentExplicitFetchMementoResolver();
ForeignKeyDescriptor foreignKeyDescriptor = fetchable.getForeignKeyDescriptor(); ForeignKeyDescriptor foreignKeyDescriptor = fetchable.getForeignKeyDescriptor();
final String associationKeyPropertyName; final String associationKeyPropertyName;
final NavigablePath associationKeyFetchPath; final NavigablePath associationKeyFetchPath;
if ( fetchable.getReferencedPropertyName() == null ) { if ( fetchable.getReferencedPropertyName() == null ) {
associationKeyPropertyName = fetchable.getEntityMappingType().getIdentifierMapping().getPartName(); associationKeyPropertyName = fetchable.getEntityMappingType().getIdentifierMapping().getPartName();
associationKeyFetchPath = relativePath.append( associationKeyPropertyName ); associationKeyFetchPath = relativePath.getValue().append( associationKeyPropertyName );
} }
else { else {
associationKeyPropertyName = fetchable.getReferencedPropertyName(); associationKeyPropertyName = fetchable.getReferencedPropertyName();
NavigablePath path = relativePath; NavigablePath path = relativePath.getValue();
for ( String part : associationKeyPropertyName.split( "\\." ) ) { for ( String part : associationKeyPropertyName.split( "\\." ) ) {
path = path.append( part ); path = path.append( part );
} }
associationKeyFetchPath = path; associationKeyFetchPath = path;
} }
final FetchBuilder explicitAssociationKeyFetchBuilder = fetchBuilderResolver final FetchBuilder explicitAssociationKeyFetchBuilder = fetchBuilderResolver
.apply( associationKeyFetchPath.getFullPath() ); .apply( relativePath.getKey() + "." + associationKeyPropertyName );
final Map<NavigablePath, FetchBuilder> fetchBuilders; final Map<NavigablePath, FetchBuilder> fetchBuilders;
if ( explicitAssociationKeyFetchBuilder == null ) { if ( explicitAssociationKeyFetchBuilder == null ) {
final MappingType partMappingType = foreignKeyDescriptor.getPartMappingType(); final MappingType partMappingType = foreignKeyDescriptor.getPartMappingType();

View File

@ -383,6 +383,7 @@ import org.hibernate.sql.results.graph.FetchParent;
import org.hibernate.sql.results.graph.Fetchable; import org.hibernate.sql.results.graph.Fetchable;
import org.hibernate.sql.results.graph.FetchableContainer; import org.hibernate.sql.results.graph.FetchableContainer;
import org.hibernate.sql.results.graph.instantiation.internal.DynamicInstantiation; import org.hibernate.sql.results.graph.instantiation.internal.DynamicInstantiation;
import org.hibernate.sql.results.graph.internal.ImmutableFetchList;
import org.hibernate.sql.results.internal.SqlSelectionImpl; import org.hibernate.sql.results.internal.SqlSelectionImpl;
import org.hibernate.sql.results.internal.StandardEntityGraphTraversalStateImpl; import org.hibernate.sql.results.internal.StandardEntityGraphTraversalStateImpl;
import org.hibernate.type.BasicType; import org.hibernate.type.BasicType;
@ -7137,7 +7138,7 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
// .getOrMakeJavaDescriptor( namedClass ); // .getOrMakeJavaDescriptor( namedClass );
} }
public void addFetch(List<Fetch> fetches, FetchParent fetchParent, Fetchable fetchable, Boolean isKeyFetchable) { private void addFetch(ImmutableFetchList.Builder fetches, FetchParent fetchParent, Fetchable fetchable, Boolean isKeyFetchable) {
final NavigablePath resolvedNavigablePath = fetchParent.resolveNavigablePath( fetchable ); final NavigablePath resolvedNavigablePath = fetchParent.resolveNavigablePath( fetchable );
final Map.Entry<Integer, List<SqlSelection>> sqlSelectionsToTrack = trackedFetchSelectionsForGroup.get( resolvedNavigablePath ); final Map.Entry<Integer, List<SqlSelection>> sqlSelectionsToTrack = trackedFetchSelectionsForGroup.get( resolvedNavigablePath );
final int sqlSelectionStartIndexForFetch; final int sqlSelectionStartIndexForFetch;
@ -7333,28 +7334,28 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
} }
@Override @Override
public List<Fetch> visitNestedFetches(FetchParent fetchParent) { public ImmutableFetchList visitNestedFetches(FetchParent fetchParent) {
final SqlAstQueryPartProcessingStateImpl processingState = (SqlAstQueryPartProcessingStateImpl) getCurrentProcessingState(); final SqlAstQueryPartProcessingStateImpl processingState = (SqlAstQueryPartProcessingStateImpl) getCurrentProcessingState();
final FetchParent nestingFetchParent = processingState.getNestingFetchParent(); final FetchParent nestingFetchParent = processingState.getNestingFetchParent();
processingState.setNestingFetchParent( fetchParent ); processingState.setNestingFetchParent( fetchParent );
final List<Fetch> fetches = visitFetches( fetchParent ); final ImmutableFetchList fetches = visitFetches( fetchParent );
processingState.setNestingFetchParent( nestingFetchParent ); processingState.setNestingFetchParent( nestingFetchParent );
return fetches; return fetches;
} }
@Override @Override
public List<Fetch> visitFetches(FetchParent fetchParent) { public ImmutableFetchList visitFetches(FetchParent fetchParent) {
final FetchableContainer referencedMappingContainer = fetchParent.getReferencedMappingContainer(); final FetchableContainer referencedMappingContainer = fetchParent.getReferencedMappingContainer();
final int keySize = referencedMappingContainer.getNumberOfKeyFetchables(); final int keySize = referencedMappingContainer.getNumberOfKeyFetchables();
final int size = referencedMappingContainer.getNumberOfFetchables(); final int size = referencedMappingContainer.getNumberOfFetchables();
final List<Fetch> fetches = CollectionHelper.arrayList( keySize + size ); final ImmutableFetchList.Builder fetches = new ImmutableFetchList.Builder( referencedMappingContainer );
for ( int i = 0; i < keySize; i++ ) { for ( int i = 0; i < keySize; i++ ) {
addFetch( fetches, fetchParent, referencedMappingContainer.getKeyFetchable( i ), true ); addFetch( fetches, fetchParent, referencedMappingContainer.getKeyFetchable( i ), true );
} }
for ( int i = 0; i < size; i++ ) { for ( int i = 0; i < size; i++ ) {
addFetch( fetches, fetchParent, referencedMappingContainer.getFetchable( i ), false ); addFetch( fetches, fetchParent, referencedMappingContainer.getFetchable( i ), false );
} }
return fetches; return fetches.build();
} }
private boolean shouldExplicitFetch(Integer maxDepth, Fetchable fetchable) { private boolean shouldExplicitFetch(Integer maxDepth, Fetchable fetchable) {

View File

@ -6,12 +6,9 @@
*/ */
package org.hibernate.sql.results.graph; package org.hibernate.sql.results.graph;
import java.util.Collections;
import java.util.List;
import org.hibernate.metamodel.mapping.EntityVersionMapping; import org.hibernate.metamodel.mapping.EntityVersionMapping;
import org.hibernate.metamodel.model.domain.NavigableRole;
import org.hibernate.spi.NavigablePath; import org.hibernate.spi.NavigablePath;
import org.hibernate.sql.results.graph.internal.ImmutableFetchList;
import org.hibernate.type.descriptor.java.JavaType; import org.hibernate.type.descriptor.java.JavaType;
/** /**
@ -21,7 +18,9 @@ public abstract class AbstractFetchParent implements FetchParent {
private final FetchableContainer fetchContainer; private final FetchableContainer fetchContainer;
private final NavigablePath navigablePath; private final NavigablePath navigablePath;
private List<Fetch> fetches; private ImmutableFetchList fetches = ImmutableFetchList.EMPTY;
private boolean hasJoinFetches;
private boolean containsCollectionFetches;
public AbstractFetchParent(FetchableContainer fetchContainer, NavigablePath navigablePath) { public AbstractFetchParent(FetchableContainer fetchContainer, NavigablePath navigablePath) {
this.fetchContainer = fetchContainer; this.fetchContainer = fetchContainer;
@ -29,12 +28,14 @@ public abstract class AbstractFetchParent implements FetchParent {
} }
public void afterInitialize(FetchParent fetchParent, DomainResultCreationState creationState) { public void afterInitialize(FetchParent fetchParent, DomainResultCreationState creationState) {
assert fetches == null; assert fetches == ImmutableFetchList.EMPTY;
resetFetches( creationState.visitFetches( fetchParent ) ); resetFetches( creationState.visitFetches( fetchParent ) );
} }
protected void resetFetches(final List<Fetch> newFetches) { protected void resetFetches(ImmutableFetchList newFetches) {
this.fetches = Collections.unmodifiableList( newFetches ); this.fetches = newFetches;
this.hasJoinFetches = newFetches.hasJoinFetches();
this.containsCollectionFetches = newFetches.containsCollectionFetches();
} }
public FetchableContainer getFetchContainer() { public FetchableContainer getFetchContainer() {
@ -57,35 +58,25 @@ public abstract class AbstractFetchParent implements FetchParent {
} }
@Override @Override
public List<Fetch> getFetches() { public ImmutableFetchList getFetches() {
return fetches == null ? Collections.emptyList() : fetches; return fetches;
} }
@Override @Override
public Fetch findFetch(final Fetchable fetchable) { public Fetch findFetch(final Fetchable fetchable) {
if ( fetches == null ) {
return null;
}
//Iterate twice so we can perform the cheapest checks on each item first:
for ( int i = 0; i < fetches.size(); i++ ) {
final Fetch fetch = fetches.get( i );
if ( fetchable == fetch.getFetchedMapping() ) {
return fetch;
}
}
if ( fetchable instanceof EntityVersionMapping ) { if ( fetchable instanceof EntityVersionMapping ) {
//Second iteration performs the slightly more expensive checks, necessary for EntityVersionMapping: return fetches.get( ( (EntityVersionMapping) fetchable ).getVersionAttribute() );
final NavigableRole navigableRole = fetchable.getNavigableRole();
for ( int i = 0; i < fetches.size(); i++ ) {
final Fetch fetch = fetches.get( i );
if ( fetch.getFetchedMapping().getNavigableRole().equals( navigableRole ) ) {
return fetch;
}
} }
return fetches.get( fetchable );
} }
return null; @Override
public boolean hasJoinFetches() {
return hasJoinFetches;
}
@Override
public boolean containsCollectionFetches() {
return containsCollectionFetches;
} }
} }

View File

@ -9,12 +9,22 @@ package org.hibernate.sql.results.graph;
import java.util.List; import java.util.List;
import org.hibernate.Incubating; import org.hibernate.Incubating;
import org.hibernate.engine.FetchTiming;
import org.hibernate.metamodel.mapping.AssociationKey; import org.hibernate.metamodel.mapping.AssociationKey;
import org.hibernate.metamodel.mapping.EntityDiscriminatorMapping;
import org.hibernate.metamodel.mapping.EntityIdentifierMapping;
import org.hibernate.metamodel.mapping.EntityMappingType;
import org.hibernate.metamodel.mapping.ForeignKeyDescriptor; import org.hibernate.metamodel.mapping.ForeignKeyDescriptor;
import org.hibernate.metamodel.mapping.ModelPart; import org.hibernate.metamodel.mapping.ModelPart;
import org.hibernate.spi.EntityIdentifierNavigablePath;
import org.hibernate.spi.NavigablePath; import org.hibernate.spi.NavigablePath;
import org.hibernate.sql.ast.spi.SqlAliasBaseManager; import org.hibernate.sql.ast.spi.SqlAliasBaseManager;
import org.hibernate.sql.ast.spi.SqlAstCreationState; import org.hibernate.sql.ast.spi.SqlAstCreationState;
import org.hibernate.sql.results.graph.basic.BasicFetch;
import org.hibernate.sql.results.graph.entity.EntityResultGraphNode;
import org.hibernate.sql.results.graph.internal.ImmutableFetchList;
import static org.hibernate.query.results.ResultsHelper.attributeName;
/** /**
* Contains state related to building {@link DomainResult} and * Contains state related to building {@link DomainResult} and
@ -77,6 +87,39 @@ public interface DomainResultCreationState {
*/ */
ModelPart resolveModelPart(NavigablePath navigablePath); ModelPart resolveModelPart(NavigablePath navigablePath);
default Fetch visitIdentifierFetch(EntityResultGraphNode fetchParent) {
final EntityIdentifierMapping identifierMapping = fetchParent.getEntityValuedModelPart()
.getEntityMappingType()
.getIdentifierMapping();
return fetchParent.generateFetchableFetch(
(Fetchable) identifierMapping,
new EntityIdentifierNavigablePath( fetchParent.getNavigablePath(), attributeName( identifierMapping ) ),
FetchTiming.IMMEDIATE,
true,
null,
this
);
}
default BasicFetch<?> visitDiscriminatorFetch(EntityResultGraphNode fetchParent) {
final EntityMappingType entityDescriptor = fetchParent.getEntityValuedModelPart().getEntityMappingType();
final EntityDiscriminatorMapping discriminatorMapping = entityDescriptor.getDiscriminatorMapping();
// No need to fetch the discriminator if this type does not have subclasses
if ( discriminatorMapping != null && entityDescriptor.hasSubclasses() ) {
return discriminatorMapping.generateFetch(
fetchParent,
fetchParent.getNavigablePath().append( EntityDiscriminatorMapping.ROLE_NAME ),
FetchTiming.IMMEDIATE,
true,
null,
this
);
}
else {
return null;
}
}
/** /**
* Visit fetches for the given parent. * Visit fetches for the given parent.
* *
@ -108,9 +151,9 @@ public interface DomainResultCreationState {
* are built/accessed. Comes down to how we'd know whether to join fetch or select fetch. Simply pass * are built/accessed. Comes down to how we'd know whether to join fetch or select fetch. Simply pass
* along FetchStyle? * along FetchStyle?
*/ */
List<Fetch> visitFetches(FetchParent fetchParent); ImmutableFetchList visitFetches(FetchParent fetchParent);
List<Fetch> visitNestedFetches(FetchParent fetchParent); ImmutableFetchList visitNestedFetches(FetchParent fetchParent);
boolean isResolvingCircularFetch(); boolean isResolvingCircularFetch();

View File

@ -6,6 +6,7 @@
*/ */
package org.hibernate.sql.results.graph; package org.hibernate.sql.results.graph;
import java.util.Iterator;
import java.util.List; import java.util.List;
import org.hibernate.internal.log.SubSystemLogging; import org.hibernate.internal.log.SubSystemLogging;
@ -114,12 +115,9 @@ public class DomainResultGraphPrinter {
// visitKeyGraphNode( identifierFetch, lastInBranch ); // visitKeyGraphNode( identifierFetch, lastInBranch );
// } // }
final int numberOfFetches = fetchParent.getFetches().size(); for ( Iterator<Fetch> iterator = fetchParent.getFetches().iterator(); iterator.hasNext(); ) {
final Fetch fetch = iterator.next();
for ( int i = 0; i < numberOfFetches; i++ ) { final boolean lastInBranch = !iterator.hasNext();
final Fetch fetch = fetchParent.getFetches().get( i );
final boolean lastInBranch = i + 1 == numberOfFetches;
visitGraphNode( fetch, lastInBranch ); visitGraphNode( fetch, lastInBranch );
} }
} }

View File

@ -0,0 +1,83 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.sql.results.graph;
import java.util.function.Consumer;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
import org.hibernate.Incubating;
import org.hibernate.engine.FetchTiming;
import org.hibernate.mapping.IndexedConsumer;
import org.hibernate.metamodel.mapping.AttributeMapping;
import org.hibernate.sql.results.graph.basic.BasicFetch;
import org.hibernate.sql.results.graph.collection.internal.EagerCollectionFetch;
import org.hibernate.sql.results.graph.embeddable.EmbeddableResultGraphNode;
import org.hibernate.sql.results.graph.internal.ImmutableFetchList;
/**
* This is essentially a List of Fetch(es), but exposing
* an interface which is more suitable to our needs; in particular
* it expresses the immutable nature of this structure, and allows
* us to extend it with additional convenience methods such as
* {@link #indexedForEach(IndexedConsumer)}.
* And additional reason for the custom interface is to allow
* custom implementations which can be highly optimised as
* necessary for our specific needs; for example the
* implementation {@link org.hibernate.sql.results.graph.internal.ImmutableFetchList}
* is able to avoid caching problems related to JDK-8180450, which would
* not have been possible with a standard generic container.
* @since 6.2
*/
@Incubating
public interface FetchList extends Iterable<Fetch> {
int size();
boolean isEmpty();
Fetch get(Fetchable fetchable);
void forEach(Consumer<? super Fetch> consumer);
void indexedForEach(IndexedConsumer<? super Fetch> consumer);
default Stream<Fetch> stream() {
return StreamSupport.stream( spliterator(), false );
}
default boolean hasJoinFetches() {
for ( Fetch fetch : this ) {
if ( fetch instanceof BasicFetch<?> || fetch.getTiming() == FetchTiming.DELAYED ) {
// That's fine
}
else if ( fetch instanceof EmbeddableResultGraphNode ) {
// Check all these fetches as well
if ( ( (EmbeddableResultGraphNode) fetch ).hasJoinFetches() ) {
return true;
}
}
else {
return true;
}
}
return false;
}
default boolean containsCollectionFetches() {
for ( Fetch fetch : this ) {
if ( fetch instanceof EagerCollectionFetch ) {
return true;
}
else if ( fetch instanceof FetchParent && ( (FetchParent) fetch ).containsCollectionFetches() ) {
return true;
}
}
return false;
}
}

View File

@ -6,8 +6,6 @@
*/ */
package org.hibernate.sql.results.graph; package org.hibernate.sql.results.graph;
import java.util.List;
import org.hibernate.Incubating; import org.hibernate.Incubating;
import org.hibernate.engine.FetchTiming; import org.hibernate.engine.FetchTiming;
import org.hibernate.metamodel.mapping.EmbeddableMappingType; import org.hibernate.metamodel.mapping.EmbeddableMappingType;
@ -17,6 +15,7 @@ import org.hibernate.metamodel.mapping.ModelPart;
import org.hibernate.metamodel.mapping.internal.ToOneAttributeMapping; import org.hibernate.metamodel.mapping.internal.ToOneAttributeMapping;
import org.hibernate.spi.EntityIdentifierNavigablePath; import org.hibernate.spi.EntityIdentifierNavigablePath;
import org.hibernate.spi.NavigablePath; import org.hibernate.spi.NavigablePath;
import org.hibernate.sql.results.graph.internal.ImmutableFetchList;
/** /**
* Contract for things that can be the parent of a fetch * Contract for things that can be the parent of a fetch
@ -84,10 +83,14 @@ public interface FetchParent extends DomainResultGraphNode {
/** /**
* Retrieve the fetches owned by this fetch source. * Retrieve the fetches owned by this fetch source.
*/ */
List<Fetch> getFetches(); ImmutableFetchList getFetches();
Fetch findFetch(Fetchable fetchable); Fetch findFetch(Fetchable fetchable);
boolean hasJoinFetches();
boolean containsCollectionFetches();
default FetchParent getRoot() { default FetchParent getRoot() {
if ( this instanceof Fetch ) { if ( this instanceof Fetch ) {
return ( (Fetch) this ).getFetchParent().getRoot(); return ( (Fetch) this ).getFetchParent().getRoot();

View File

@ -8,7 +8,9 @@ package org.hibernate.sql.results.graph;
import org.hibernate.Incubating; import org.hibernate.Incubating;
import org.hibernate.engine.FetchTiming; import org.hibernate.engine.FetchTiming;
import org.hibernate.mapping.IndexedConsumer;
import org.hibernate.metamodel.mapping.AttributeMapping; import org.hibernate.metamodel.mapping.AttributeMapping;
import org.hibernate.metamodel.mapping.EntityMappingType;
import org.hibernate.metamodel.mapping.ModelPart; import org.hibernate.metamodel.mapping.ModelPart;
import org.hibernate.spi.NavigablePath; import org.hibernate.spi.NavigablePath;
@ -24,6 +26,16 @@ public interface Fetchable extends ModelPart {
*/ */
String getFetchableName(); String getFetchableName();
/**
* The key that identifies this {@linkplain Fetchable} within a {@link FetchableContainer}.
* If this {@linkplain Fetchable} is part of {@link FetchableContainer#visitFetchables(IndexedConsumer, EntityMappingType)},
* the values is guaranteed to be between 0 (inclusive) and {@link FetchableContainer#getNumberOfFetchableKeys()} (exclusive).
* Other {@linkplain Fetchable} objects may have a special negative value.
* <p>
* The main intent of this key is to index e.g. {@link Fetch} objects in an array.
*/
int getFetchableKey();
/** /**
* The configured fetch timing and style * The configured fetch timing and style
*/ */

View File

@ -34,6 +34,13 @@ public interface FetchableContainer extends ModelPartContainer {
*/ */
int getNumberOfFetchables(); int getNumberOfFetchables();
/**
* The number of fetchables in the container
*/
default int getNumberOfFetchableKeys() {
return getNumberOfFetchables();
}
default Fetchable getKeyFetchable(int position) { default Fetchable getKeyFetchable(int position) {
List<Fetchable> fetchables = new ArrayList<>( getNumberOfKeyFetchables() ); List<Fetchable> fetchables = new ArrayList<>( getNumberOfKeyFetchables() );
visitKeyFetchables( fetchable -> fetchables.add( fetchable ), null ); visitKeyFetchables( fetchable -> fetchables.add( fetchable ), null );

View File

@ -26,6 +26,7 @@ import org.hibernate.sql.results.graph.Fetchable;
import org.hibernate.sql.results.graph.FetchableContainer; import org.hibernate.sql.results.graph.FetchableContainer;
import org.hibernate.sql.results.graph.collection.CollectionInitializer; import org.hibernate.sql.results.graph.collection.CollectionInitializer;
import org.hibernate.sql.results.graph.collection.CollectionResultGraphNode; import org.hibernate.sql.results.graph.collection.CollectionResultGraphNode;
import org.hibernate.sql.results.graph.internal.ImmutableFetchList;
import org.hibernate.type.descriptor.java.JavaType; import org.hibernate.type.descriptor.java.JavaType;
/** /**
@ -127,8 +128,8 @@ public class CollectionDomainResult implements DomainResult, CollectionResultGra
} }
@Override @Override
public List<Fetch> getFetches() { public ImmutableFetchList getFetches() {
return Collections.emptyList(); return ImmutableFetchList.EMPTY;
} }
@Override @Override
@ -136,4 +137,14 @@ public class CollectionDomainResult implements DomainResult, CollectionResultGra
return null; return null;
} }
@Override
public boolean hasJoinFetches() {
return false;
}
@Override
public boolean containsCollectionFetches() {
return false;
}
} }

View File

@ -23,11 +23,13 @@ import org.hibernate.sql.results.graph.DomainResult;
import org.hibernate.sql.results.graph.DomainResultAssembler; import org.hibernate.sql.results.graph.DomainResultAssembler;
import org.hibernate.sql.results.graph.DomainResultCreationState; import org.hibernate.sql.results.graph.DomainResultCreationState;
import org.hibernate.sql.results.graph.Fetch; import org.hibernate.sql.results.graph.Fetch;
import org.hibernate.sql.results.graph.FetchList;
import org.hibernate.sql.results.graph.FetchParent; import org.hibernate.sql.results.graph.FetchParent;
import org.hibernate.sql.results.graph.FetchParentAccess; import org.hibernate.sql.results.graph.FetchParentAccess;
import org.hibernate.sql.results.graph.Fetchable; import org.hibernate.sql.results.graph.Fetchable;
import org.hibernate.sql.results.graph.FetchableContainer; import org.hibernate.sql.results.graph.FetchableContainer;
import org.hibernate.sql.results.graph.collection.CollectionInitializer; import org.hibernate.sql.results.graph.collection.CollectionInitializer;
import org.hibernate.sql.results.graph.internal.ImmutableFetchList;
import org.hibernate.type.descriptor.java.JavaType; import org.hibernate.type.descriptor.java.JavaType;
/** /**
@ -40,7 +42,7 @@ public class EagerCollectionFetch extends CollectionFetch implements FetchParent
private final Fetch elementFetch; private final Fetch elementFetch;
private final Fetch indexFetch; private final Fetch indexFetch;
private final List<Fetch> fetches; private final ImmutableFetchList fetches;
private final CollectionInitializerProducer initializerProducer; private final CollectionInitializerProducer initializerProducer;
@ -104,17 +106,17 @@ public class EagerCollectionFetch extends CollectionFetch implements FetchParent
creationState creationState
); );
fetches = Collections.unmodifiableList( creationState.visitFetches( this ) ); fetches = creationState.visitFetches( this );
if ( fetchedAttribute.getIndexDescriptor() != null ) { if ( fetchedAttribute.getIndexDescriptor() != null ) {
assert fetches.size() == 2; assert fetches.size() == 2;
indexFetch = fetches.get( 0 ); indexFetch = fetches.get( fetchedAttribute.getIndexDescriptor() );
elementFetch = fetches.get( 1 ); elementFetch = fetches.get( fetchedAttribute.getElementDescriptor() );
} }
else { else {
if ( !fetches.isEmpty() ) { // might be empty due to fetch depth limit if ( !fetches.isEmpty() ) { // might be empty due to fetch depth limit
assert fetches.size() == 1; assert fetches.size() == 1;
indexFetch = null; indexFetch = null;
elementFetch = fetches.get( 0 ); elementFetch = fetches.get( fetchedAttribute.getElementDescriptor() );
} }
else { else {
indexFetch = null; indexFetch = null;
@ -180,7 +182,7 @@ public class EagerCollectionFetch extends CollectionFetch implements FetchParent
} }
@Override @Override
public List<Fetch> getFetches() { public ImmutableFetchList getFetches() {
return fetches; return fetches;
} }
@ -200,6 +202,18 @@ public class EagerCollectionFetch extends CollectionFetch implements FetchParent
} }
} }
@Override
public boolean hasJoinFetches() {
// This is already a fetch, so this line should actually never be hit
return true;
}
@Override
public boolean containsCollectionFetches() {
// This is already a collection fetch, so this line should actually never be hit
return true;
}
@Override @Override
public JavaType<?> getResultJavaType() { public JavaType<?> getResultJavaType() {
return getFetchedMapping().getJavaType(); return getFetchedMapping().getJavaType();

View File

@ -32,6 +32,7 @@ import org.hibernate.sql.results.graph.FetchParentAccess;
import org.hibernate.sql.results.graph.embeddable.EmbeddableInitializer; import org.hibernate.sql.results.graph.embeddable.EmbeddableInitializer;
import org.hibernate.sql.results.graph.embeddable.EmbeddableResult; import org.hibernate.sql.results.graph.embeddable.EmbeddableResult;
import org.hibernate.sql.results.graph.embeddable.EmbeddableResultGraphNode; import org.hibernate.sql.results.graph.embeddable.EmbeddableResultGraphNode;
import org.hibernate.sql.results.graph.internal.ImmutableFetchList;
import org.hibernate.type.descriptor.java.JavaType; import org.hibernate.type.descriptor.java.JavaType;
import org.hibernate.type.descriptor.jdbc.AggregateJdbcType; import org.hibernate.type.descriptor.jdbc.AggregateJdbcType;
import org.hibernate.type.spi.TypeConfiguration; import org.hibernate.type.spi.TypeConfiguration;
@ -106,9 +107,9 @@ public class AggregateEmbeddableResultImpl<T> extends AbstractFetchParent implem
this.containsAnyNonScalars = determineIfContainedAnyScalars( getFetches() ); this.containsAnyNonScalars = determineIfContainedAnyScalars( getFetches() );
} }
private static boolean determineIfContainedAnyScalars(List<Fetch> fetches) { private static boolean determineIfContainedAnyScalars(ImmutableFetchList fetches) {
for ( int i = 0; i < fetches.size(); i++ ) { for ( Fetch fetch : fetches ) {
if ( fetches.get( i ).containsAnyNonScalarResults() ) { if ( fetch.containsAnyNonScalarResults() ) {
return true; return true;
} }
} }

View File

@ -6,23 +6,15 @@
*/ */
package org.hibernate.sql.results.graph.embeddable.internal; package org.hibernate.sql.results.graph.embeddable.internal;
import java.util.ArrayList;
import java.util.List;
import org.hibernate.engine.FetchTiming; import org.hibernate.engine.FetchTiming;
import org.hibernate.metamodel.mapping.AttributeMapping;
import org.hibernate.metamodel.mapping.EmbeddableMappingType; import org.hibernate.metamodel.mapping.EmbeddableMappingType;
import org.hibernate.metamodel.mapping.EmbeddableValuedModelPart; import org.hibernate.metamodel.mapping.EmbeddableValuedModelPart;
import org.hibernate.metamodel.mapping.internal.BasicAttributeMapping; import org.hibernate.metamodel.mapping.internal.BasicAttributeMapping;
import org.hibernate.spi.NavigablePath; import org.hibernate.spi.NavigablePath;
import org.hibernate.sql.ast.SqlAstJoinType;
import org.hibernate.sql.ast.spi.FromClauseAccess;
import org.hibernate.sql.ast.spi.SqlAstCreationState; import org.hibernate.sql.ast.spi.SqlAstCreationState;
import org.hibernate.sql.ast.spi.SqlExpressionResolver; import org.hibernate.sql.ast.spi.SqlExpressionResolver;
import org.hibernate.sql.ast.spi.SqlSelection; import org.hibernate.sql.ast.spi.SqlSelection;
import org.hibernate.sql.ast.tree.expression.SqlTuple; import org.hibernate.sql.ast.tree.expression.SqlTuple;
import org.hibernate.sql.ast.tree.from.TableGroup;
import org.hibernate.sql.ast.tree.from.TableGroupJoin;
import org.hibernate.sql.results.graph.AbstractFetchParent; import org.hibernate.sql.results.graph.AbstractFetchParent;
import org.hibernate.sql.results.graph.AssemblerCreationState; import org.hibernate.sql.results.graph.AssemblerCreationState;
import org.hibernate.sql.results.graph.DomainResult; import org.hibernate.sql.results.graph.DomainResult;
@ -34,6 +26,7 @@ import org.hibernate.sql.results.graph.basic.BasicFetch;
import org.hibernate.sql.results.graph.embeddable.EmbeddableInitializer; import org.hibernate.sql.results.graph.embeddable.EmbeddableInitializer;
import org.hibernate.sql.results.graph.embeddable.EmbeddableResult; import org.hibernate.sql.results.graph.embeddable.EmbeddableResult;
import org.hibernate.sql.results.graph.embeddable.EmbeddableResultGraphNode; import org.hibernate.sql.results.graph.embeddable.EmbeddableResultGraphNode;
import org.hibernate.sql.results.graph.internal.ImmutableFetchList;
import org.hibernate.type.descriptor.java.JavaType; import org.hibernate.type.descriptor.java.JavaType;
import org.hibernate.type.spi.TypeConfiguration; import org.hibernate.type.spi.TypeConfiguration;
@ -53,7 +46,7 @@ public class EmbeddableExpressionResultImpl<T> extends AbstractFetchParent imple
super( modelPart.getEmbeddableTypeDescriptor(), navigablePath ); super( modelPart.getEmbeddableTypeDescriptor(), navigablePath );
this.resultVariable = resultVariable; this.resultVariable = resultVariable;
final List<Fetch> fetches = new ArrayList<>(); final ImmutableFetchList.Builder fetches = new ImmutableFetchList.Builder( modelPart );
final EmbeddableMappingType mappingType = modelPart.getEmbeddableTypeDescriptor(); final EmbeddableMappingType mappingType = modelPart.getEmbeddableTypeDescriptor();
final int numberOfAttributeMappings = mappingType.getNumberOfAttributeMappings(); final int numberOfAttributeMappings = mappingType.getNumberOfAttributeMappings();
final SqlAstCreationState sqlAstCreationState = creationState.getSqlAstCreationState(); final SqlAstCreationState sqlAstCreationState = creationState.getSqlAstCreationState();
@ -81,13 +74,13 @@ public class EmbeddableExpressionResultImpl<T> extends AbstractFetchParent imple
); );
} }
this.containsAnyNonScalars = determineIfContainedAnyScalars( fetches ); resetFetches( fetches.build() );
resetFetches( fetches ); this.containsAnyNonScalars = determineIfContainedAnyScalars( getFetches() );
} }
private static boolean determineIfContainedAnyScalars(List<Fetch> fetches) { private static boolean determineIfContainedAnyScalars(ImmutableFetchList fetches) {
for ( int i = 0; i < fetches.size(); i++ ) { for ( Fetch fetch : fetches ) {
if ( fetches.get( i ).containsAnyNonScalarResults() ) { if ( fetch.containsAnyNonScalarResults() ) {
return true; return true;
} }
} }

View File

@ -25,6 +25,7 @@ import org.hibernate.sql.results.graph.FetchParentAccess;
import org.hibernate.sql.results.graph.embeddable.EmbeddableInitializer; import org.hibernate.sql.results.graph.embeddable.EmbeddableInitializer;
import org.hibernate.sql.results.graph.embeddable.EmbeddableResult; import org.hibernate.sql.results.graph.embeddable.EmbeddableResult;
import org.hibernate.sql.results.graph.embeddable.EmbeddableResultGraphNode; import org.hibernate.sql.results.graph.embeddable.EmbeddableResultGraphNode;
import org.hibernate.sql.results.graph.internal.ImmutableFetchList;
import org.hibernate.type.descriptor.java.JavaType; import org.hibernate.type.descriptor.java.JavaType;
/** /**
@ -76,9 +77,9 @@ public class EmbeddableResultImpl<T> extends AbstractFetchParent implements Embe
containsAnyNonScalars = determineIfContainedAnyScalars( getFetches() ); containsAnyNonScalars = determineIfContainedAnyScalars( getFetches() );
} }
private static boolean determineIfContainedAnyScalars(List<Fetch> fetches) { private static boolean determineIfContainedAnyScalars(ImmutableFetchList fetches) {
for ( int i = 0; i < fetches.size(); i++ ) { for ( Fetch fetch : fetches ) {
if ( fetches.get( i ).containsAnyNonScalarResults() ) { if ( fetch.containsAnyNonScalarResults() ) {
return true; return true;
} }
} }

View File

@ -53,37 +53,20 @@ public abstract class AbstractEntityResultGraphNode extends AbstractFetchParent
final NavigablePath navigablePath = getNavigablePath(); final NavigablePath navigablePath = getNavigablePath();
final TableGroup entityTableGroup = creationState.getSqlAstCreationState().getFromClauseAccess() final TableGroup entityTableGroup = creationState.getSqlAstCreationState().getFromClauseAccess()
.getTableGroup( navigablePath ); .getTableGroup( navigablePath );
final EntityIdentifierNavigablePath identifierNavigablePath = new EntityIdentifierNavigablePath( navigablePath, attributeName( identifierMapping ) );
if ( navigablePath.getParent() == null && !creationState.forceIdentifierSelection() ) { if ( navigablePath.getParent() == null && !creationState.forceIdentifierSelection() ) {
identifierFetch = null; identifierFetch = null;
visitIdentifierMapping( identifierNavigablePath, creationState, identifierMapping, entityTableGroup ); visitIdentifierMapping(
new EntityIdentifierNavigablePath( navigablePath, attributeName( identifierMapping ) ),
creationState,
identifierMapping,
entityTableGroup
);
} }
else { else {
identifierFetch = ( (Fetchable) identifierMapping ).generateFetch( identifierFetch = creationState.visitIdentifierFetch( this );
fetchParent,
identifierNavigablePath,
FetchTiming.IMMEDIATE,
true,
null,
creationState
);
} }
final EntityDiscriminatorMapping discriminatorMapping = entityDescriptor.getDiscriminatorMapping(); discriminatorFetch = creationState.visitDiscriminatorFetch( this );
// No need to fetch the discriminator if this type does not have subclasses
if ( discriminatorMapping != null && entityDescriptor.hasSubclasses() ) {
discriminatorFetch = discriminatorMapping.generateFetch(
fetchParent,
navigablePath.append( EntityDiscriminatorMapping.ROLE_NAME ),
FetchTiming.IMMEDIATE,
true,
null,
creationState
);
}
else {
discriminatorFetch = null;
}
final EntityRowIdMapping rowIdMapping = entityDescriptor.getRowIdMapping(); final EntityRowIdMapping rowIdMapping = entityDescriptor.getRowIdMapping();
if ( rowIdMapping == null ) { if ( rowIdMapping == null ) {

View File

@ -16,6 +16,7 @@ import org.hibernate.sql.results.graph.FetchParent;
import org.hibernate.sql.results.graph.Fetchable; import org.hibernate.sql.results.graph.Fetchable;
import org.hibernate.sql.results.graph.entity.EntityFetch; import org.hibernate.sql.results.graph.entity.EntityFetch;
import org.hibernate.sql.results.graph.entity.EntityValuedFetchable; import org.hibernate.sql.results.graph.entity.EntityValuedFetchable;
import org.hibernate.sql.results.graph.internal.ImmutableFetchList;
/** /**
* @author Steve Ebersole * @author Steve Ebersole
@ -55,8 +56,8 @@ public abstract class AbstractNonJoinedEntityFetch implements EntityFetch {
} }
@Override @Override
public List<Fetch> getFetches() { public ImmutableFetchList getFetches() {
return Collections.emptyList(); return ImmutableFetchList.EMPTY;
} }
@Override @Override
@ -64,6 +65,16 @@ public abstract class AbstractNonJoinedEntityFetch implements EntityFetch {
return null; return null;
} }
@Override
public boolean hasJoinFetches() {
return false;
}
@Override
public boolean containsCollectionFetches() {
return false;
}
@Override @Override
public EntityMappingType getReferencedMappingType() { public EntityMappingType getReferencedMappingType() {
return fetchedModelPart.getEntityMappingType(); return fetchedModelPart.getEntityMappingType();

View File

@ -0,0 +1,141 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.sql.results.graph.internal;
import java.util.Collections;
import java.util.Iterator;
import java.util.function.Consumer;
import org.hibernate.mapping.IndexedConsumer;
import org.hibernate.metamodel.mapping.AttributeMapping;
import org.hibernate.persister.internal.ImmutableAttributeMappingList;
import org.hibernate.sql.results.graph.Fetch;
import org.hibernate.sql.results.graph.FetchList;
import org.hibernate.sql.results.graph.Fetchable;
import org.hibernate.sql.results.graph.FetchableContainer;
public final class ImmutableFetchList implements FetchList {
public static ImmutableFetchList EMPTY = new ImmutableFetchList();
private final Fetch[] fetches;
private ImmutableFetchList() {
this.fetches = null;
}
private ImmutableFetchList(Fetch[] fetches) {
assert fetches != null;
this.fetches = fetches;
}
@Override
public int size() {
if ( fetches == null ) {
return 0;
}
int size = 0;
for ( Fetch fetch : fetches ) {
if ( fetch != null ) {
size++;
}
}
return size;
}
@Override
public boolean isEmpty() {
return fetches == null;
}
@Override
public Fetch get(Fetchable fetchable) {
return fetches == null ? null : fetches[fetchable.getFetchableKey()];
}
@Override
public void forEach(Consumer<? super Fetch> consumer) {
if ( fetches != null ) {
for ( Fetch fetch : fetches ) {
if ( fetch != null ) {
consumer.accept( fetch );
}
}
}
}
@Override
public void indexedForEach(IndexedConsumer<? super Fetch> consumer) {
if ( fetches != null ) {
int index = 0;
for ( Fetch fetch : fetches ) {
if ( fetch != null ) {
consumer.accept( index++, fetch );
}
}
}
}
@Override
public Iterator<Fetch> iterator() {
if ( fetches == null ) {
return Collections.emptyIterator();
}
return new FetchIterator();
}
private final class FetchIterator implements Iterator<Fetch> {
private int idx;
public FetchIterator() {
assert ImmutableFetchList.this.fetches != null;
this.idx = 0;
while (ImmutableFetchList.this.fetches[idx] == null) {
idx++;
}
}
@Override
public boolean hasNext() {
return idx < ImmutableFetchList.this.fetches.length;
}
@Override
public Fetch next() {
final Fetch fetch = ImmutableFetchList.this.fetches[idx++];
while ( idx < ImmutableFetchList.this.fetches.length ) {
if ( ImmutableFetchList.this.fetches[idx] != null ) {
break;
}
idx++;
}
return fetch;
}
}
public static class Builder {
private final Fetch[] fetches;
public Builder(FetchableContainer container) {
this.fetches = new Fetch[container.getNumberOfFetchableKeys()];
}
public void add(Fetch fetch) {
fetches[fetch.getFetchedMapping().getFetchableKey()] = fetch;
}
public ImmutableFetchList build() {
for ( Fetch fetch : fetches ) {
if ( fetch != null ) {
return new ImmutableFetchList( fetches );
}
}
return EMPTY;
}
}
}

View File

@ -12,8 +12,6 @@ import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.internal.FetchingScrollableResultsImpl; import org.hibernate.internal.FetchingScrollableResultsImpl;
import org.hibernate.internal.ScrollableResultsImpl; import org.hibernate.internal.ScrollableResultsImpl;
import org.hibernate.sql.results.graph.DomainResult; import org.hibernate.sql.results.graph.DomainResult;
import org.hibernate.sql.results.graph.Fetch;
import org.hibernate.sql.results.graph.collection.internal.EagerCollectionFetch;
import org.hibernate.sql.results.graph.entity.EntityResult; import org.hibernate.sql.results.graph.entity.EntityResult;
import org.hibernate.sql.results.jdbc.spi.JdbcValuesMapping; import org.hibernate.sql.results.jdbc.spi.JdbcValuesMapping;
import org.hibernate.sql.results.jdbc.spi.JdbcValues; import org.hibernate.sql.results.jdbc.spi.JdbcValues;
@ -74,17 +72,11 @@ public class ScrollableResultsConsumer<R> implements ResultsConsumer<ScrollableR
private boolean containsCollectionFetches(JdbcValuesMapping valuesMapping) { private boolean containsCollectionFetches(JdbcValuesMapping valuesMapping) {
final List<DomainResult<?>> domainResults = valuesMapping.getDomainResults(); final List<DomainResult<?>> domainResults = valuesMapping.getDomainResults();
for ( DomainResult domainResult : domainResults ) { for ( DomainResult<?> domainResult : domainResults ) {
if ( domainResult instanceof EntityResult ) { if ( domainResult instanceof EntityResult && ( (EntityResult) domainResult ).containsCollectionFetches() ) {
EntityResult entityResult = (EntityResult) domainResult;
final List<Fetch> fetches = entityResult.getFetches();
for ( Fetch fetch : fetches ) {
if ( fetch instanceof EagerCollectionFetch ) {
return true; return true;
} }
} }
}
}
return false; return false;
} }
} }

View File

@ -54,6 +54,7 @@ import org.hibernate.sql.results.graph.entity.EntityFetch;
import org.hibernate.sql.results.graph.entity.EntityResult; import org.hibernate.sql.results.graph.entity.EntityResult;
import org.hibernate.sql.results.graph.entity.internal.EntityDelayedFetchImpl; import org.hibernate.sql.results.graph.entity.internal.EntityDelayedFetchImpl;
import org.hibernate.sql.results.graph.entity.internal.EntityFetchJoinedImpl; import org.hibernate.sql.results.graph.entity.internal.EntityFetchJoinedImpl;
import org.hibernate.sql.results.graph.internal.ImmutableFetchList;
import org.hibernate.testing.TestForIssue; import org.hibernate.testing.TestForIssue;
import org.hibernate.testing.orm.junit.DomainModel; import org.hibernate.testing.orm.junit.DomainModel;
@ -190,13 +191,12 @@ public class CriteriaEntityGraphTest implements SessionFactoryScopeAware {
Fetchable fetchable = getFetchable( "company", Person.class ); Fetchable fetchable = getFetchable( "company", Person.class );
final Fetch companyFetch = ownerEntityResult.findFetch( fetchable ); final Fetch companyFetch = ownerEntityResult.findFetch( fetchable );
List<Fetch> fetches = ownerEntityResult.getFetches();
assertThat( companyFetch, notNullValue() ); assertThat( companyFetch, notNullValue() );
final EntityResult companyEntityResult = ( (EntityFetchJoinedImpl) companyFetch).getEntityResult(); final EntityResult companyEntityResult = ( (EntityFetchJoinedImpl) companyFetch).getEntityResult();
assertThat( companyEntityResult.getFetches(), hasSize( 1 ) ); assertThat( companyEntityResult.getFetches().size(), is( 1 ) );
final Fetch shipAddressesFetch = companyEntityResult.getFetches().get( 0 ); final Fetch shipAddressesFetch = companyEntityResult.getFetches().iterator().next();
assertThat( shipAddressesFetch.getFetchedMapping().getPartName(), is( "shipAddresses" ) ); assertThat( shipAddressesFetch.getFetchedMapping().getPartName(), is( "shipAddresses" ) );
assertThat( shipAddressesFetch, instanceOf( DelayedCollectionFetch.class ) ); assertThat( shipAddressesFetch, instanceOf( DelayedCollectionFetch.class ) );
} ); } );
@ -348,9 +348,9 @@ public class CriteriaEntityGraphTest implements SessionFactoryScopeAware {
final EntityResult entityResult = (EntityResult) domainResult; final EntityResult entityResult = (EntityResult) domainResult;
assertThat( entityResult.getReferencedModePart().getJavaType().getJavaTypeClass(), assignableTo( expectedEntityJpaClass ) ); assertThat( entityResult.getReferencedModePart().getJavaType().getJavaTypeClass(), assignableTo( expectedEntityJpaClass ) );
assertThat( entityResult.getFetches(), hasSize( 1 ) ); assertThat( entityResult.getFetches().size(), is( 1 ) );
final Fetch fetch = entityResult.getFetches().get( 0 ); final Fetch fetch = entityResult.getFetches().iterator().next();
assertThat( fetch, instanceOf( EntityFetch.class ) ); assertThat( fetch, instanceOf( EntityFetch.class ) );
final EntityFetch entityFetch = (EntityFetch) fetch; final EntityFetch entityFetch = (EntityFetch) fetch;

View File

@ -189,9 +189,9 @@ public class EntityGraphLoadPlanBuilderTest implements SessionFactoryScopeAware
assertThat( companyFetch, notNullValue() ); assertThat( companyFetch, notNullValue() );
final EntityResult companyEntityResult = ( (EntityFetchJoinedImpl) companyFetch).getEntityResult(); final EntityResult companyEntityResult = ( (EntityFetchJoinedImpl) companyFetch).getEntityResult();
assertThat( companyEntityResult.getFetches(), hasSize( 1 ) ); assertThat( companyEntityResult.getFetches().size(), is( 1 ) );
final Fetch shipAddressesFetch = companyEntityResult.getFetches().get( 0 ); final Fetch shipAddressesFetch = companyEntityResult.getFetches().iterator().next();
assertThat( shipAddressesFetch.getFetchedMapping().getPartName(), is( "shipAddresses" ) ); assertThat( shipAddressesFetch.getFetchedMapping().getPartName(), is( "shipAddresses" ) );
assertThat( shipAddressesFetch, instanceOf( DelayedCollectionFetch.class ) ); assertThat( shipAddressesFetch, instanceOf( DelayedCollectionFetch.class ) );
} ); } );
@ -337,9 +337,9 @@ public class EntityGraphLoadPlanBuilderTest implements SessionFactoryScopeAware
final EntityResult entityResult = (EntityResult) domainResult; final EntityResult entityResult = (EntityResult) domainResult;
assertThat( entityResult.getReferencedModePart().getJavaType().getJavaTypeClass(), assignableTo( expectedEntityJpaClass ) ); assertThat( entityResult.getReferencedModePart().getJavaType().getJavaTypeClass(), assignableTo( expectedEntityJpaClass ) );
assertThat( entityResult.getFetches(), hasSize( 1 ) ); assertThat( entityResult.getFetches().size(), is( 1 ) );
final Fetch fetch = entityResult.getFetches().get( 0 ); final Fetch fetch = entityResult.getFetches().iterator().next();
assertThat( fetch, instanceOf( EntityFetch.class ) ); assertThat( fetch, instanceOf( EntityFetch.class ) );
final EntityFetch entityFetch = (EntityFetch) fetch; final EntityFetch entityFetch = (EntityFetch) fetch;

View File

@ -191,9 +191,9 @@ public class HqlEntityGraphTest implements SessionFactoryScopeAware {
assertThat( companyFetch, notNullValue() ); assertThat( companyFetch, notNullValue() );
final EntityResult companyEntityResult = ( (EntityFetchJoinedImpl) companyFetch).getEntityResult(); final EntityResult companyEntityResult = ( (EntityFetchJoinedImpl) companyFetch).getEntityResult();
assertThat( companyEntityResult.getFetches(), hasSize( 1 ) ); assertThat( companyEntityResult.getFetches().size(), is( 1 ) );
final Fetch shipAddressesFetch = companyEntityResult.getFetches().get( 0 ); final Fetch shipAddressesFetch = companyEntityResult.getFetches().iterator().next();
assertThat( shipAddressesFetch.getFetchedMapping().getPartName(), is( "shipAddresses" ) ); assertThat( shipAddressesFetch.getFetchedMapping().getPartName(), is( "shipAddresses" ) );
assertThat( shipAddressesFetch, instanceOf( DelayedCollectionFetch.class ) ); assertThat( shipAddressesFetch, instanceOf( DelayedCollectionFetch.class ) );
} ); } );
@ -345,9 +345,9 @@ public class HqlEntityGraphTest implements SessionFactoryScopeAware {
final EntityResult entityResult = (EntityResult) domainResult; final EntityResult entityResult = (EntityResult) domainResult;
assertThat( entityResult.getReferencedModePart().getJavaType().getJavaTypeClass(), assignableTo( expectedEntityJpaClass ) ); assertThat( entityResult.getReferencedModePart().getJavaType().getJavaTypeClass(), assignableTo( expectedEntityJpaClass ) );
assertThat( entityResult.getFetches(), hasSize( 1 ) ); assertThat( entityResult.getFetches().size(), is( 1 ) );
final Fetch fetch = entityResult.getFetches().get( 0 ); final Fetch fetch = entityResult.getFetches().iterator().next();
assertThat( fetch, instanceOf( EntityFetch.class ) ); assertThat( fetch, instanceOf( EntityFetch.class ) );
final EntityFetch entityFetch = (EntityFetch) fetch; final EntityFetch entityFetch = (EntityFetch) fetch;

View File

@ -73,12 +73,12 @@ public class LoadPlanBuilderTest {
final EntityResult entityResult = (EntityResult) domainResult; final EntityResult entityResult = (EntityResult) domainResult;
assertThat( entityResult.getFetches() ).hasSize( 2 ); assertThat( entityResult.getFetches() ).hasSize( 2 );
final Fetch txtFetch = entityResult.getFetches().get( 0 ); final Fetch txtFetch = entityResult.getFetches().get( entityDescriptor.findAttributeMapping( "msgTxt" ) );
assertThat( txtFetch ).isNotNull(); assertThat( txtFetch ).isNotNull();
assertThat( txtFetch.getFetchedMapping().getFetchableName() ).isEqualTo( "msgTxt" ); assertThat( txtFetch.getFetchedMapping().getFetchableName() ).isEqualTo( "msgTxt" );
assertThat( txtFetch.getTiming() ).isEqualTo( FetchTiming.IMMEDIATE ); assertThat( txtFetch.getTiming() ).isEqualTo( FetchTiming.IMMEDIATE );
final Fetch posterFetch = entityResult.getFetches().get( 1 ); final Fetch posterFetch = entityResult.getFetches().get( entityDescriptor.findAttributeMapping( "poster" ) );
assertThat( posterFetch ).isNotNull(); assertThat( posterFetch ).isNotNull();
assertThat( posterFetch.getFetchedMapping().getFetchableName() ).isEqualTo( "poster" ); assertThat( posterFetch.getFetchedMapping().getFetchableName() ).isEqualTo( "poster" );
assertThat( posterFetch.getTiming() ).isEqualTo( FetchTiming.DELAYED ); assertThat( posterFetch.getTiming() ).isEqualTo( FetchTiming.DELAYED );
@ -114,12 +114,12 @@ public class LoadPlanBuilderTest {
final EntityResult entityResult = (EntityResult) domainResult; final EntityResult entityResult = (EntityResult) domainResult;
assertThat( entityResult.getFetches() ).hasSize( 2 ); assertThat( entityResult.getFetches() ).hasSize( 2 );
final Fetch txtFetch = entityResult.getFetches().get( 0 ); final Fetch txtFetch = entityResult.getFetches().get( entityDescriptor.findAttributeMapping( "msgTxt" ) );
assertThat( txtFetch ).isNotNull(); assertThat( txtFetch ).isNotNull();
assertThat( txtFetch.getFetchedMapping().getFetchableName() ).isEqualTo( "msgTxt" ); assertThat( txtFetch.getFetchedMapping().getFetchableName() ).isEqualTo( "msgTxt" );
assertThat( txtFetch.getTiming() ).isEqualTo( FetchTiming.IMMEDIATE ); assertThat( txtFetch.getTiming() ).isEqualTo( FetchTiming.IMMEDIATE );
final Fetch posterFetch = entityResult.getFetches().get( 1 ); final Fetch posterFetch = entityResult.getFetches().get( entityDescriptor.findAttributeMapping( "poster" ) );
assertThat( posterFetch ).isNotNull(); assertThat( posterFetch ).isNotNull();
assertThat( posterFetch.getFetchedMapping().getFetchableName() ).isEqualTo( "poster" ); assertThat( posterFetch.getFetchedMapping().getFetchableName() ).isEqualTo( "poster" );
assertThat( posterFetch.getTiming() ).isEqualTo( FetchTiming.IMMEDIATE ); assertThat( posterFetch.getTiming() ).isEqualTo( FetchTiming.IMMEDIATE );

View File

@ -36,6 +36,7 @@ import org.hibernate.sql.results.graph.collection.internal.EagerCollectionFetch;
import org.hibernate.sql.results.graph.DomainResult; import org.hibernate.sql.results.graph.DomainResult;
import org.hibernate.sql.results.graph.entity.EntityResult; import org.hibernate.sql.results.graph.entity.EntityResult;
import org.hibernate.sql.results.graph.Fetch; import org.hibernate.sql.results.graph.Fetch;
import org.hibernate.sql.results.graph.internal.ImmutableFetchList;
import org.hibernate.testing.orm.junit.DomainModel; import org.hibernate.testing.orm.junit.DomainModel;
import org.hibernate.testing.orm.junit.SessionFactory; import org.hibernate.testing.orm.junit.SessionFactory;
@ -85,22 +86,22 @@ public class MappedFetchTests {
assertThat( domainResult, instanceOf( EntityResult.class ) ); assertThat( domainResult, instanceOf( EntityResult.class ) );
final EntityResult entityResult = (EntityResult) domainResult; final EntityResult entityResult = (EntityResult) domainResult;
final List<Fetch> fetches = entityResult.getFetches(); final ImmutableFetchList fetches = entityResult.getFetches();
// name + both lists // name + both lists
assertThat( fetches.size(), is( 3 ) ); assertThat( fetches.size(), is( 3 ) );
// order is alphabetical... // order is alphabetical...
final Fetch nameFetch = fetches.get( 0 ); final Fetch nameFetch = fetches.get( rootEntityDescriptor.findAttributeMapping( "name" ) );
assertThat( nameFetch.getFetchedMapping().getFetchableName(), is( "name" ) ); assertThat( nameFetch.getFetchedMapping().getFetchableName(), is( "name" ) );
assertThat( nameFetch, instanceOf( BasicFetch.class ) ); assertThat( nameFetch, instanceOf( BasicFetch.class ) );
final Fetch nickNamesFetch = fetches.get( 1 ); final Fetch nickNamesFetch = fetches.get( rootEntityDescriptor.findAttributeMapping( "nickNames" ) );
assertThat( nickNamesFetch.getFetchedMapping().getFetchableName(), is( "nickNames" ) ); assertThat( nickNamesFetch.getFetchedMapping().getFetchableName(), is( "nickNames" ) );
assertThat( nickNamesFetch, instanceOf( EagerCollectionFetch.class ) ); assertThat( nickNamesFetch, instanceOf( EagerCollectionFetch.class ) );
final Fetch simpleEntitiesFetch = fetches.get( 2 ); final Fetch simpleEntitiesFetch = fetches.get( rootEntityDescriptor.findAttributeMapping( "simpleEntities" ) );
assertThat( simpleEntitiesFetch.getFetchedMapping().getFetchableName(), is( "simpleEntities" ) ); assertThat( simpleEntitiesFetch.getFetchedMapping().getFetchableName(), is( "simpleEntities" ) );
assertThat( simpleEntitiesFetch, instanceOf( DelayedCollectionFetch.class ) ); assertThat( simpleEntitiesFetch, instanceOf( DelayedCollectionFetch.class ) );