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.Fetchable;
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.stat.spi.StatisticsImplementor;
@ -413,12 +414,12 @@ public abstract class AbstractNaturalIdLoader<T> implements NaturalIdLoader<T> {
return results.get( 0 );
}
private static List<Fetch> visitFetches(
private static ImmutableFetchList visitFetches(
FetchParent fetchParent,
LoaderSqlAstCreationState creationState) {
final FetchableContainer fetchableContainer = fetchParent.getReferencedMappingContainer();
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++ ) {
final Fetchable fetchable = fetchableContainer.getFetchable( i );
final NavigablePath navigablePath = fetchParent.resolveNavigablePath( fetchable );
@ -432,6 +433,6 @@ public abstract class AbstractNaturalIdLoader<T> implements NaturalIdLoader<T> {
);
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.JdbcParameterBindings;
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.spi.ListResultsConsumer;
import org.hibernate.type.BasicType;
@ -76,7 +77,7 @@ class DatabaseSnapshotExecutor {
sqlAliasBaseManager,
new FromClauseIndex( null ),
LockOptions.NONE,
(fetchParent, creationState) -> Collections.emptyList(),
(fetchParent, creationState) -> ImmutableFetchList.EMPTY,
true,
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.collection.internal.CollectionDomainResult;
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.StandardEntityGraphTraversalStateImpl;
@ -648,12 +649,12 @@ public class LoaderSelectBuilder {
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() ) {
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(
fetchParent,
creationState,
@ -671,13 +672,13 @@ public class LoaderSelectBuilder {
for ( int i = 0; i < size; i++ ) {
processor.accept( referencedMappingContainer.getFetchable( i ), false );
}
return fetches;
return fetches.build();
}
private BiConsumer<Fetchable, Boolean> createFetchableBiConsumer(
FetchParent fetchParent,
LoaderSqlAstCreationState creationState,
List<Fetch> fetches) {
ImmutableFetchList.Builder fetches) {
return (fetchable, isKeyFetchable) -> {
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.Fetch;
import org.hibernate.sql.results.graph.FetchParent;
import org.hibernate.sql.results.graph.internal.ImmutableFetchList;
/**
* Helper used when generating the database-snapshot select query
@ -45,7 +46,7 @@ import org.hibernate.sql.results.graph.FetchParent;
public class LoaderSqlAstCreationState
implements SqlAstQueryPartProcessingState, SqlAstCreationState, DomainResultCreationState, QueryOptions {
public interface FetchProcessor {
List<Fetch> visitFetches(FetchParent fetchParent, LoaderSqlAstCreationState creationState);
ImmutableFetchList visitFetches(FetchParent fetchParent, LoaderSqlAstCreationState creationState);
}
private final SqlAliasBaseManager sqlAliasBaseManager;
@ -119,15 +120,15 @@ public class LoaderSqlAstCreationState
}
@Override
public List<Fetch> visitFetches(FetchParent fetchParent) {
public ImmutableFetchList visitFetches(FetchParent fetchParent) {
return fetchProcessor.visitFetches( fetchParent, this );
}
@Override
public List<Fetch> visitNestedFetches(FetchParent fetchParent) {
public ImmutableFetchList visitNestedFetches(FetchParent fetchParent) {
final FetchParent nestingFetchParent = processingState.getNestingFetchParent();
processingState.setNestingFetchParent( fetchParent );
final List<Fetch> fetches = fetchProcessor.visitFetches( fetchParent, this );
final ImmutableFetchList fetches = fetchProcessor.visitFetches( fetchParent, this );
processingState.setNestingFetchParent( nestingFetchParent );
return fetches;
}

View File

@ -14,4 +14,8 @@ import org.hibernate.metamodel.mapping.internal.SingleAttributeIdentifierMapping
* @author Steve Ebersole
*/
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 {
@Override
default int getFetchableKey() {
return -1;
}
@Override
default IdentifierValue getUnsavedStrategy() {
return IdentifierValue.UNDEFINED;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -8,7 +8,6 @@ package org.hibernate.metamodel.mapping.internal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.function.BiConsumer;
@ -19,7 +18,6 @@ import org.hibernate.NotYetImplementedFor6Exception;
import org.hibernate.engine.spi.PersistenceContext;
import org.hibernate.engine.spi.SessionFactoryImplementor;
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.MultiNaturalIdLoaderStandard;
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.FetchableContainer;
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.RowProcessingState;
import org.hibernate.type.descriptor.java.JavaType;
@ -453,7 +452,9 @@ public class CompoundNaturalIdMapping extends AbstractNaturalIdMapping implement
private final CompoundNaturalIdMapping naturalIdMapping;
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;
@ -468,7 +469,9 @@ public class CompoundNaturalIdMapping extends AbstractNaturalIdMapping implement
this.arrayJtd = arrayJtd;
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
public List<Fetch> getFetches() {
public ImmutableFetchList getFetches() {
return fetches;
}
@Override
public Fetch findFetch(Fetchable fetchable) {
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;
}
}
@Override
public boolean hasJoinFetches() {
return hasJoinFetches;
}
return null;
@Override
public boolean containsCollectionFetches() {
return containsCollectionFetches;
}
}
@ -541,10 +546,10 @@ public class CompoundNaturalIdMapping extends AbstractNaturalIdMapping implement
private final CompoundNaturalIdMapping naturalIdMapping;
private final JavaType<Object[]> jtd;
private final List<DomainResultAssembler<?>> subAssemblers;
private final DomainResultAssembler<?>[] subAssemblers;
private AssemblerImpl(
List<Fetch> fetches,
ImmutableFetchList fetches,
NavigablePath navigablePath,
CompoundNaturalIdMapping naturalIdMapping,
JavaType<Object[]> jtd,
@ -557,11 +562,10 @@ public class CompoundNaturalIdMapping extends AbstractNaturalIdMapping implement
// we just "need it" as an impl detail for handling Fetches
final InitializerImpl initializer = new InitializerImpl( navigablePath, naturalIdMapping );
this.subAssemblers = CollectionHelper.arrayList( fetches.size() );
for ( int i = 0; i < fetches.size(); i++ ) {
final Fetch fetch = fetches.get( i );
final DomainResultAssembler<?> fetchAssembler = fetch.createAssembler( initializer, creationState );
subAssemblers.add( fetchAssembler );
this.subAssemblers = new DomainResultAssembler[fetches.size()];
int i = 0;
for ( Fetch fetch : fetches ) {
subAssemblers[i++] = fetch.createAssembler( initializer, creationState );
}
}
@ -569,9 +573,9 @@ public class CompoundNaturalIdMapping extends AbstractNaturalIdMapping implement
public Object[] assemble(
RowProcessingState rowProcessingState,
JdbcValuesSourceProcessingOptions options) {
final Object[] result = new Object[ subAssemblers.size() ];
for ( int i = 0; i < subAssemblers.size(); i++ ) {
result[ i ] = subAssemblers.get( i ).assemble( rowProcessingState, options );
final Object[] result = new Object[ subAssemblers.length ];
for ( int i = 0; i < subAssemblers.length; i++ ) {
result[ i ] = subAssemblers[i].assemble( rowProcessingState, options );
}
return result;
}

View File

@ -71,6 +71,7 @@ public class DiscriminatedAssociationAttributeMapping
JavaType<?> baseAssociationJtd,
ManagedMappingType declaringType,
int stateArrayPosition,
int fetchableIndex,
AttributeMetadata attributeMetadata,
FetchTiming fetchTiming,
PropertyAccess propertyAccess,
@ -81,6 +82,7 @@ public class DiscriminatedAssociationAttributeMapping
super(
bootProperty.getName(),
stateArrayPosition,
fetchableIndex,
attributeMetadata,
fetchTiming,
FetchStyle.SELECT,
@ -188,8 +190,10 @@ public class DiscriminatedAssociationAttributeMapping
public Fetchable getFetchable(int position) {
switch ( position ) {
case 0:
assert getDiscriminatorPart().getFetchableKey() == 0;
return getDiscriminatorPart();
case 1:
assert getKeyPart().getFetchableKey() == 1;
return getKeyPart();
}
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.FetchParentAccess;
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.RowProcessingState;
import org.hibernate.type.AnyType;
@ -413,7 +414,7 @@ public class DiscriminatedAssociationMapping implements MappingType, FetchOption
private Fetch discriminatorValueFetch;
private Fetch keyValueFetch;
private List<Fetch> fetches;
private ImmutableFetchList fetches;
public AnyValuedResultGraphNode(
NavigablePath navigablePath,
@ -425,11 +426,11 @@ public class DiscriminatedAssociationMapping implements MappingType, FetchOption
}
protected void afterInitialize(DomainResultCreationState creationState) {
this.fetches = Collections.unmodifiableList( creationState.visitFetches( this ) );
this.fetches = creationState.visitFetches( this );
assert fetches.size() == 2;
discriminatorValueFetch = fetches.get( 0 );
keyValueFetch = fetches.get( 1 );
discriminatorValueFetch = fetches.get( graphedPart.getDiscriminatorPart() );
keyValueFetch = fetches.get( graphedPart.getKeyPart() );
}
public Fetch getDiscriminatorValueFetch() {
@ -470,7 +471,7 @@ public class DiscriminatedAssociationMapping implements MappingType, FetchOption
}
@Override
public List<Fetch> getFetches() {
public ImmutableFetchList getFetches() {
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" );
}
@Override
public boolean hasJoinFetches() {
return false;
}
@Override
public boolean containsCollectionFetches() {
return false;
}
}
private static class AnyValuedResult<T> extends AnyValuedResultGraphNode implements DomainResult<T> {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -27,6 +27,7 @@ public class VirtualEmbeddedAttributeMapping extends EmbeddedAttributeMapping im
String name,
NavigableRole navigableRole,
int stateArrayPosition,
int fetchableIndex,
String tableExpression,
AttributeMetadata attributeMetadata,
String parentInjectionAttributeName,
@ -39,6 +40,7 @@ public class VirtualEmbeddedAttributeMapping extends EmbeddedAttributeMapping im
name,
navigableRole,
stateArrayPosition,
fetchableIndex,
tableExpression,
attributeMetadata,
parentInjectionAttributeName,
@ -54,6 +56,7 @@ public class VirtualEmbeddedAttributeMapping extends EmbeddedAttributeMapping im
String name,
NavigableRole navigableRole,
int stateArrayPosition,
int fetchableIndex,
String tableExpression,
AttributeMetadata attributeMetadata,
PropertyAccess parentInjectionAttributePropertyAccess,
@ -66,6 +69,7 @@ public class VirtualEmbeddedAttributeMapping extends EmbeddedAttributeMapping im
name,
navigableRole,
stateArrayPosition,
fetchableIndex,
tableExpression,
attributeMetadata,
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.JdbcMutationOperation;
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.generator.Generator;
import org.hibernate.generator.InMemoryGenerator;
@ -934,7 +935,7 @@ public abstract class AbstractCollectionPersister
new SqlAliasBaseManager(),
new SimpleFromClauseAccessImpl(),
LockOptions.NONE,
(fetchParent, creationState) -> new ArrayList<>(),
(fetchParent, creationState) -> ImmutableFetchList.EMPTY,
true,
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.embeddable.EmbeddableResultGraphNode;
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.stat.spi.StatisticsImplementor;
import org.hibernate.tuple.NonIdentifierAttribute;
@ -1797,10 +1798,10 @@ public abstract class AbstractEntityPersister
return expression;
}
private List<Fetch> fetchProcessor(FetchParent fetchParent, LoaderSqlAstCreationState creationState) {
private ImmutableFetchList fetchProcessor(FetchParent fetchParent, LoaderSqlAstCreationState creationState) {
final FetchableContainer fetchableContainer = fetchParent.getReferencedMappingContainer();
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++ ) {
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) {
@ -4652,6 +4653,7 @@ public abstract class AbstractEntityPersister
final NonIdentifierAttribute[] properties = currentEntityMetamodel.getProperties();
AttributeMappingsMap.Builder mappingsBuilder = AttributeMappingsMap.builder();
int fetchableIndex = getFetchableIndexOffset();
for ( int i = 0; i < currentEntityMetamodel.getPropertySpan(); i++ ) {
final NonIdentifierAttribute runtimeAttrDefinition = properties[i];
final Property bootProperty = bootEntityDescriptor.getProperty( runtimeAttrDefinition.getName() );
@ -4664,6 +4666,7 @@ public abstract class AbstractEntityPersister
runtimeAttrDefinition,
bootProperty,
stateArrayPosition++,
fetchableIndex++,
creationProcess
)
);
@ -4701,6 +4704,7 @@ public abstract class AbstractEntityPersister
}
final ImmutableAttributeMappingList.Builder builder = new ImmutableAttributeMappingList.Builder( attributeMappings.size() );
visitSubTypeAttributeMappings( attributeMapping -> builder.add( attributeMapping ) );
assert superMappingType != null || builder.assertFetchableIndexes();
staticFetchableList = builder.build();
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) {
final EntityInstantiator instantiator = getRepresentationStrategy().getInstantiator();
final Supplier<?> templateInstanceCreator;
@ -5206,6 +5234,7 @@ public abstract class AbstractEntityPersister
NonIdentifierAttribute tupleAttrDefinition,
Property bootProperty,
int stateArrayPosition,
int fetchableIndex,
MappingModelCreationProcess creationProcess) {
final SessionFactoryImplementor sessionFactory = creationProcess.getCreationContext().getSessionFactory();
final JdbcServices jdbcServices = sessionFactory.getJdbcServices();
@ -5229,6 +5258,7 @@ public abstract class AbstractEntityPersister
attrName,
getNavigableRole().append( bootProperty.getName() ),
stateArrayPosition,
fetchableIndex,
bootProperty,
this,
(BasicType<?>) attrType,
@ -5318,6 +5348,7 @@ public abstract class AbstractEntityPersister
attrName,
getNavigableRole().append( bootProperty.getName() ),
stateArrayPosition,
fetchableIndex,
bootProperty,
this,
(BasicType<?>) attrType,
@ -5362,6 +5393,7 @@ public abstract class AbstractEntityPersister
baseAssociationJtd,
this,
stateArrayPosition,
fetchableIndex,
attributeMetadataAccess,
bootProperty.isLazy() ? FetchTiming.DELAYED : FetchTiming.IMMEDIATE,
propertyAccess,
@ -5375,6 +5407,7 @@ public abstract class AbstractEntityPersister
return MappingModelCreationHelper.buildEmbeddedAttributeMapping(
attrName,
stateArrayPosition,
fetchableIndex,
bootProperty,
this,
(CompositeType) attrType,
@ -5389,6 +5422,7 @@ public abstract class AbstractEntityPersister
return MappingModelCreationHelper.buildPluralAttributeMapping(
attrName,
stateArrayPosition,
fetchableIndex,
bootProperty,
this,
propertyAccess,
@ -5402,6 +5436,7 @@ public abstract class AbstractEntityPersister
attrName,
getNavigableRole().append( attrName ),
stateArrayPosition,
fetchableIndex,
bootProperty,
this,
this,
@ -5659,6 +5694,11 @@ public abstract class AbstractEntityPersister
return getStaticFetchableList().size();
}
@Override
public int getNumberOfFetchableKeys() {
return superMappingType == null ? getNumberOfFetchables() : getRootEntityDescriptor().getNumberOfFetchables();
}
@Override
public int getNumberOfKeyFetchables() {
return 0;

View File

@ -90,6 +90,13 @@ public final class ImmutableAttributeMappingList implements AttributeMappingsLis
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,
JdbcMapping jdbcMapping,
BasicEntityIdentifierMapping delegate) {
super( delegate.getAttributeName(), selectionExpression, expressible, jdbcMapping );
super( delegate.getAttributeName(), selectionExpression, expressible, jdbcMapping, -1 );
this.delegate = delegate;
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -8,7 +8,6 @@ package org.hibernate.query.results;
import java.util.AbstractMap;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
import java.util.function.Function;
@ -17,7 +16,6 @@ import org.hibernate.Internal;
import org.hibernate.LockMode;
import org.hibernate.engine.FetchTiming;
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.StandardStack;
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.Fetchable;
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.type.descriptor.java.JavaType;
import org.hibernate.type.spi.TypeConfiguration;
@ -126,9 +126,8 @@ public class DomainResultCreationStateImpl
return jdbcResultsMetadata;
}
public NavigablePath getCurrentRelativePath() {
final Map.Entry<String, NavigablePath> entry = relativePathStack.getCurrent();
return entry == null ? null : entry.getValue();
public Map.Entry<String, NavigablePath> getCurrentRelativePath() {
return relativePathStack.getCurrent();
}
public void pushExplicitFetchMementoResolver(Function<String, FetchBuilder> resolver) {
@ -332,26 +331,106 @@ public class DomainResultCreationStateImpl
}
@Override
public List<Fetch> visitNestedFetches(FetchParent fetchParent) {
public ImmutableFetchList visitNestedFetches(FetchParent fetchParent) {
final FetchParent oldNestingFetchParent = this.nestingFetchParent;
this.nestingFetchParent = fetchParent;
final List<Fetch> fetches = visitFetches( fetchParent );
final ImmutableFetchList fetches = visitFetches( fetchParent );
this.nestingFetchParent = oldNestingFetchParent;
return fetches;
}
@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 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() );
final Consumer<Fetchable> fetchableConsumer = fetchable -> {
private Consumer<Fetchable> createFetchableConsumer(FetchParent fetchParent, ImmutableFetchList.Builder fetches) {
return fetchable -> {
final String fetchableName = fetchable.getFetchableName();
Map.Entry<String, NavigablePath> currentEntry;
if ( relativePathStack.isEmpty() ) {
currentEntry = new AbstractMap.SimpleEntry<>(
getRelativePath( "", fetchable, fetchableContainer ),
getRelativePath( "", fetchable ),
new NavigablePath( fetchableName )
);
}
@ -359,7 +438,7 @@ public class DomainResultCreationStateImpl
final Map.Entry<String, NavigablePath> oldEntry = relativePathStack.getCurrent();
final String key = oldEntry.getKey();
currentEntry = new AbstractMap.SimpleEntry<>(
getRelativePath( key, fetchable, fetchableContainer ),
getRelativePath( key, fetchable ),
oldEntry.getValue().append( fetchableName )
);
}
@ -384,8 +463,9 @@ public class DomainResultCreationStateImpl
final Association association = (Association) fetchable;
final ForeignKeyDescriptor foreignKeyDescriptor = association.getForeignKeyDescriptor();
final String partName = attributeName( foreignKeyDescriptor.getSide( association.getSideNature().inverse() )
.getModelPart());
final String partName = attributeName(
foreignKeyDescriptor.getSide( association.getSideNature().inverse() ).getModelPart()
);
// If there are no fetch builders for this association, we only want to fetch the FK
if ( explicitFetchBuilder == null && fetchBuilderLegacy == null && partName != null ) {
@ -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 {
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) {
private String getRelativePath(String oldEntry, Fetchable fetchable) {
if ( fetchable instanceof AttributeMapping || fetchable instanceof SingleAttributeIdentifierMapping || fetchable instanceof BasicValuedCollectionPart ) {
if ( !oldEntry.equals( "" ) ) {
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.embeddable.EmbeddableResultGraphNode;
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.JdbcValuesMappingProducer;
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.
// If we don't do that, there is no way to fetch joined inheritance entities
if ( polymorphic && ( legacyFetchBuilders == null || legacyFetchBuilders.isEmpty() )
&& !hasJoinFetches( entityResult.getFetches() ) ) {
&& !entityResult.hasJoinFetches() ) {
final Set<String> aliases = new TreeSet<>( String.CASE_INSENSITIVE_ORDER );
final AbstractEntityPersister entityPersister = (AbstractEntityPersister) entityResult.getReferencedMappingContainer()
.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(
int valuesArrayPosition,
Consumer<SqlSelection> sqlSelectionConsumer,

View File

@ -6,19 +6,11 @@
*/
package org.hibernate.query.results.complete;
import java.util.Collections;
import java.util.List;
import java.util.function.Function;
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.internal.SingleAttributeIdentifierMapping;
import org.hibernate.spi.EntityIdentifierNavigablePath;
import org.hibernate.spi.NavigablePath;
import org.hibernate.query.results.ResultsHelper;
import org.hibernate.sql.ast.spi.SqlAstCreationState;
import org.hibernate.sql.results.graph.AssemblerCreationState;
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.Initializer;
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.internal.EntityAssembler;
import org.hibernate.sql.results.graph.entity.internal.EntityResultInitializer;
import org.hibernate.sql.results.graph.internal.ImmutableFetchList;
/**
* @author Steve Ebersole
@ -42,12 +34,13 @@ public class EntityResultImpl implements EntityResult {
private final Fetch identifierFetch;
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 LockMode lockMode;
@SuppressWarnings( { "PointlessNullCheck" } )
public EntityResultImpl(
NavigablePath navigablePath,
EntityValuedModelPart entityValuedModelPart,
@ -78,49 +71,12 @@ public class EntityResultImpl implements EntityResult {
}
);
this.identifierFetch = creationState.visitIdentifierFetch( this );
this.discriminatorFetch = discriminatorFetchBuilder.apply( this );
final List<Fetch> localFetches = creationState.visitFetches( this );
final EntityIdentifierMapping identifierMapping = entityValuedModelPart
.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();
}
this.fetches = creationState.visitFetches( this );
this.hasJoinFetches = fetches.hasJoinFetches();
this.containsCollectionFetches = fetches.containsCollectionFetches();
}
@Override
@ -144,20 +100,23 @@ public class EntityResultImpl implements EntityResult {
}
@Override
public List<Fetch> getFetches() {
public ImmutableFetchList getFetches() {
return fetches;
}
@Override
public Fetch findFetch(Fetchable fetchable) {
final String name = fetchable.getFetchableName();
for ( int i = 0; i < fetches.size(); i++ ) {
final Fetch fetch = fetches.get( i );
if ( fetch.getFetchedMapping().getFetchableName().equals( name ) ) {
return fetch;
}
}
return null;
return fetches.get( fetchable );
}
@Override
public boolean hasJoinFetches() {
return hasJoinFetches;
}
@Override
public boolean containsCollectionFetches() {
return containsCollectionFetches;
}
@Override

View File

@ -199,13 +199,13 @@ public class DynamicFetchBuilderLegacy implements DynamicFetchBuilder, NativeQue
}
}
try {
final NavigablePath currentRelativePath = creationState.getCurrentRelativePath();
final Map.Entry<String, NavigablePath> currentRelativePath = creationState.getCurrentRelativePath();
final String prefix;
if ( currentRelativePath == null ) {
prefix = "";
}
else {
prefix = currentRelativePath.getFullPath()
prefix = currentRelativePath.getKey()
.replace( ELEMENT_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.PluralAttributeMapping;
import org.hibernate.metamodel.mapping.SelectableConsumer;
import org.hibernate.metamodel.mapping.internal.EmbeddedAttributeMapping;
import org.hibernate.metamodel.mapping.internal.ToOneAttributeMapping;
import org.hibernate.query.NativeQuery;
import org.hibernate.spi.NavigablePath;
import org.hibernate.query.results.DomainResultCreationStateImpl;
import org.hibernate.query.results.ResultsHelper;
import org.hibernate.query.results.ResultSetMappingSqlSelection;
import org.hibernate.sql.ast.spi.SqlExpressionResolver;
import org.hibernate.sql.ast.tree.from.TableGroup;
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.FetchParent;
import org.hibernate.sql.results.graph.Fetchable;
import org.hibernate.sql.results.graph.embeddable.EmbeddableValuedFetchable;
import org.hibernate.sql.results.jdbc.spi.JdbcValuesMetadata;
import static org.hibernate.sql.ast.spi.SqlExpressionResolver.createColumnReferenceKey;
@ -114,7 +113,7 @@ public class DynamicFetchBuilderStandard
creationStateImpl
);
}
else if ( attributeMapping instanceof EmbeddedAttributeMapping ) {
else if ( attributeMapping instanceof EmbeddableValuedFetchable ) {
attributeMapping.forEachSelectable( selectableConsumer );
return parent.generateFetchableFetch(
attributeMapping,

View File

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

View File

@ -51,13 +51,13 @@ public class ImplicitFetchBuilderEmbeddable implements ImplicitFetchBuilder {
this.fetchPath = fetchPath;
this.fetchable = fetchable;
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 int size = fetchable.getNumberOfFetchables();
final Map<NavigablePath, FetchBuilder> fetchBuilders = CollectionHelper.linkedMapOfSize( size );
for ( int i = 0; i < size; 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() );
if ( explicitFetchBuilder == null ) {
fetchBuilders.put(

View File

@ -48,25 +48,25 @@ public class ImplicitFetchBuilderEntity implements ImplicitFetchBuilder {
this.fetchPath = fetchPath;
this.fetchable = fetchable;
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();
ForeignKeyDescriptor foreignKeyDescriptor = fetchable.getForeignKeyDescriptor();
final String associationKeyPropertyName;
final NavigablePath associationKeyFetchPath;
if ( fetchable.getReferencedPropertyName() == null ) {
associationKeyPropertyName = fetchable.getEntityMappingType().getIdentifierMapping().getPartName();
associationKeyFetchPath = relativePath.append( associationKeyPropertyName );
associationKeyFetchPath = relativePath.getValue().append( associationKeyPropertyName );
}
else {
associationKeyPropertyName = fetchable.getReferencedPropertyName();
NavigablePath path = relativePath;
NavigablePath path = relativePath.getValue();
for ( String part : associationKeyPropertyName.split( "\\." ) ) {
path = path.append( part );
}
associationKeyFetchPath = path;
}
final FetchBuilder explicitAssociationKeyFetchBuilder = fetchBuilderResolver
.apply( associationKeyFetchPath.getFullPath() );
.apply( relativePath.getKey() + "." + associationKeyPropertyName );
final Map<NavigablePath, FetchBuilder> fetchBuilders;
if ( explicitAssociationKeyFetchBuilder == null ) {
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.FetchableContainer;
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.StandardEntityGraphTraversalStateImpl;
import org.hibernate.type.BasicType;
@ -7137,7 +7138,7 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
// .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 Map.Entry<Integer, List<SqlSelection>> sqlSelectionsToTrack = trackedFetchSelectionsForGroup.get( resolvedNavigablePath );
final int sqlSelectionStartIndexForFetch;
@ -7333,28 +7334,28 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
}
@Override
public List<Fetch> visitNestedFetches(FetchParent fetchParent) {
public ImmutableFetchList visitNestedFetches(FetchParent fetchParent) {
final SqlAstQueryPartProcessingStateImpl processingState = (SqlAstQueryPartProcessingStateImpl) getCurrentProcessingState();
final FetchParent nestingFetchParent = processingState.getNestingFetchParent();
processingState.setNestingFetchParent( fetchParent );
final List<Fetch> fetches = visitFetches( fetchParent );
final ImmutableFetchList fetches = visitFetches( fetchParent );
processingState.setNestingFetchParent( nestingFetchParent );
return fetches;
}
@Override
public List<Fetch> visitFetches(FetchParent fetchParent) {
public ImmutableFetchList visitFetches(FetchParent fetchParent) {
final FetchableContainer referencedMappingContainer = fetchParent.getReferencedMappingContainer();
final int keySize = referencedMappingContainer.getNumberOfKeyFetchables();
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++ ) {
addFetch( fetches, fetchParent, referencedMappingContainer.getKeyFetchable( i ), true );
}
for ( int i = 0; i < size; i++ ) {
addFetch( fetches, fetchParent, referencedMappingContainer.getFetchable( i ), false );
}
return fetches;
return fetches.build();
}
private boolean shouldExplicitFetch(Integer maxDepth, Fetchable fetchable) {

View File

@ -6,12 +6,9 @@
*/
package org.hibernate.sql.results.graph;
import java.util.Collections;
import java.util.List;
import org.hibernate.metamodel.mapping.EntityVersionMapping;
import org.hibernate.metamodel.model.domain.NavigableRole;
import org.hibernate.spi.NavigablePath;
import org.hibernate.sql.results.graph.internal.ImmutableFetchList;
import org.hibernate.type.descriptor.java.JavaType;
/**
@ -21,7 +18,9 @@ public abstract class AbstractFetchParent implements FetchParent {
private final FetchableContainer fetchContainer;
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) {
this.fetchContainer = fetchContainer;
@ -29,12 +28,14 @@ public abstract class AbstractFetchParent implements FetchParent {
}
public void afterInitialize(FetchParent fetchParent, DomainResultCreationState creationState) {
assert fetches == null;
assert fetches == ImmutableFetchList.EMPTY;
resetFetches( creationState.visitFetches( fetchParent ) );
}
protected void resetFetches(final List<Fetch> newFetches) {
this.fetches = Collections.unmodifiableList( newFetches );
protected void resetFetches(ImmutableFetchList newFetches) {
this.fetches = newFetches;
this.hasJoinFetches = newFetches.hasJoinFetches();
this.containsCollectionFetches = newFetches.containsCollectionFetches();
}
public FetchableContainer getFetchContainer() {
@ -57,35 +58,25 @@ public abstract class AbstractFetchParent implements FetchParent {
}
@Override
public List<Fetch> getFetches() {
return fetches == null ? Collections.emptyList() : fetches;
public ImmutableFetchList getFetches() {
return fetches;
}
@Override
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 ) {
//Second iteration performs the slightly more expensive checks, necessary for EntityVersionMapping:
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( ( (EntityVersionMapping) fetchable ).getVersionAttribute() );
}
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 org.hibernate.Incubating;
import org.hibernate.engine.FetchTiming;
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.ModelPart;
import org.hibernate.spi.EntityIdentifierNavigablePath;
import org.hibernate.spi.NavigablePath;
import org.hibernate.sql.ast.spi.SqlAliasBaseManager;
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
@ -77,6 +87,39 @@ public interface DomainResultCreationState {
*/
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.
*
@ -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
* along FetchStyle?
*/
List<Fetch> visitFetches(FetchParent fetchParent);
ImmutableFetchList visitFetches(FetchParent fetchParent);
List<Fetch> visitNestedFetches(FetchParent fetchParent);
ImmutableFetchList visitNestedFetches(FetchParent fetchParent);
boolean isResolvingCircularFetch();

View File

@ -6,6 +6,7 @@
*/
package org.hibernate.sql.results.graph;
import java.util.Iterator;
import java.util.List;
import org.hibernate.internal.log.SubSystemLogging;
@ -114,12 +115,9 @@ public class DomainResultGraphPrinter {
// visitKeyGraphNode( identifierFetch, lastInBranch );
// }
final int numberOfFetches = fetchParent.getFetches().size();
for ( int i = 0; i < numberOfFetches; i++ ) {
final Fetch fetch = fetchParent.getFetches().get( i );
final boolean lastInBranch = i + 1 == numberOfFetches;
for ( Iterator<Fetch> iterator = fetchParent.getFetches().iterator(); iterator.hasNext(); ) {
final Fetch fetch = iterator.next();
final boolean lastInBranch = !iterator.hasNext();
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;
import java.util.List;
import org.hibernate.Incubating;
import org.hibernate.engine.FetchTiming;
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.spi.EntityIdentifierNavigablePath;
import org.hibernate.spi.NavigablePath;
import org.hibernate.sql.results.graph.internal.ImmutableFetchList;
/**
* 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.
*/
List<Fetch> getFetches();
ImmutableFetchList getFetches();
Fetch findFetch(Fetchable fetchable);
boolean hasJoinFetches();
boolean containsCollectionFetches();
default FetchParent getRoot() {
if ( this instanceof Fetch ) {
return ( (Fetch) this ).getFetchParent().getRoot();

View File

@ -8,7 +8,9 @@ package org.hibernate.sql.results.graph;
import org.hibernate.Incubating;
import org.hibernate.engine.FetchTiming;
import org.hibernate.mapping.IndexedConsumer;
import org.hibernate.metamodel.mapping.AttributeMapping;
import org.hibernate.metamodel.mapping.EntityMappingType;
import org.hibernate.metamodel.mapping.ModelPart;
import org.hibernate.spi.NavigablePath;
@ -24,6 +26,16 @@ public interface Fetchable extends ModelPart {
*/
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
*/

View File

@ -34,6 +34,13 @@ public interface FetchableContainer extends ModelPartContainer {
*/
int getNumberOfFetchables();
/**
* The number of fetchables in the container
*/
default int getNumberOfFetchableKeys() {
return getNumberOfFetchables();
}
default Fetchable getKeyFetchable(int position) {
List<Fetchable> fetchables = new ArrayList<>( getNumberOfKeyFetchables() );
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.collection.CollectionInitializer;
import org.hibernate.sql.results.graph.collection.CollectionResultGraphNode;
import org.hibernate.sql.results.graph.internal.ImmutableFetchList;
import org.hibernate.type.descriptor.java.JavaType;
/**
@ -127,8 +128,8 @@ public class CollectionDomainResult implements DomainResult, CollectionResultGra
}
@Override
public List<Fetch> getFetches() {
return Collections.emptyList();
public ImmutableFetchList getFetches() {
return ImmutableFetchList.EMPTY;
}
@Override
@ -136,4 +137,14 @@ public class CollectionDomainResult implements DomainResult, CollectionResultGra
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.DomainResultCreationState;
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.FetchParentAccess;
import org.hibernate.sql.results.graph.Fetchable;
import org.hibernate.sql.results.graph.FetchableContainer;
import org.hibernate.sql.results.graph.collection.CollectionInitializer;
import org.hibernate.sql.results.graph.internal.ImmutableFetchList;
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 indexFetch;
private final List<Fetch> fetches;
private final ImmutableFetchList fetches;
private final CollectionInitializerProducer initializerProducer;
@ -104,17 +106,17 @@ public class EagerCollectionFetch extends CollectionFetch implements FetchParent
creationState
);
fetches = Collections.unmodifiableList( creationState.visitFetches( this ) );
fetches = creationState.visitFetches( this );
if ( fetchedAttribute.getIndexDescriptor() != null ) {
assert fetches.size() == 2;
indexFetch = fetches.get( 0 );
elementFetch = fetches.get( 1 );
indexFetch = fetches.get( fetchedAttribute.getIndexDescriptor() );
elementFetch = fetches.get( fetchedAttribute.getElementDescriptor() );
}
else {
if ( !fetches.isEmpty() ) { // might be empty due to fetch depth limit
assert fetches.size() == 1;
indexFetch = null;
elementFetch = fetches.get( 0 );
elementFetch = fetches.get( fetchedAttribute.getElementDescriptor() );
}
else {
indexFetch = null;
@ -180,7 +182,7 @@ public class EagerCollectionFetch extends CollectionFetch implements FetchParent
}
@Override
public List<Fetch> getFetches() {
public ImmutableFetchList getFetches() {
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
public JavaType<?> getResultJavaType() {
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.EmbeddableResult;
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.jdbc.AggregateJdbcType;
import org.hibernate.type.spi.TypeConfiguration;
@ -106,9 +107,9 @@ public class AggregateEmbeddableResultImpl<T> extends AbstractFetchParent implem
this.containsAnyNonScalars = determineIfContainedAnyScalars( getFetches() );
}
private static boolean determineIfContainedAnyScalars(List<Fetch> fetches) {
for ( int i = 0; i < fetches.size(); i++ ) {
if ( fetches.get( i ).containsAnyNonScalarResults() ) {
private static boolean determineIfContainedAnyScalars(ImmutableFetchList fetches) {
for ( Fetch fetch : fetches ) {
if ( fetch.containsAnyNonScalarResults() ) {
return true;
}
}

View File

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

View File

@ -53,37 +53,20 @@ public abstract class AbstractEntityResultGraphNode extends AbstractFetchParent
final NavigablePath navigablePath = getNavigablePath();
final TableGroup entityTableGroup = creationState.getSqlAstCreationState().getFromClauseAccess()
.getTableGroup( navigablePath );
final EntityIdentifierNavigablePath identifierNavigablePath = new EntityIdentifierNavigablePath( navigablePath, attributeName( identifierMapping ) );
if ( navigablePath.getParent() == null && !creationState.forceIdentifierSelection() ) {
identifierFetch = null;
visitIdentifierMapping( identifierNavigablePath, creationState, identifierMapping, entityTableGroup );
visitIdentifierMapping(
new EntityIdentifierNavigablePath( navigablePath, attributeName( identifierMapping ) ),
creationState,
identifierMapping,
entityTableGroup
);
}
else {
identifierFetch = ( (Fetchable) identifierMapping ).generateFetch(
fetchParent,
identifierNavigablePath,
FetchTiming.IMMEDIATE,
true,
null,
creationState
);
identifierFetch = creationState.visitIdentifierFetch( this );
}
final EntityDiscriminatorMapping discriminatorMapping = entityDescriptor.getDiscriminatorMapping();
// 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;
}
discriminatorFetch = creationState.visitDiscriminatorFetch( this );
final EntityRowIdMapping rowIdMapping = entityDescriptor.getRowIdMapping();
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.entity.EntityFetch;
import org.hibernate.sql.results.graph.entity.EntityValuedFetchable;
import org.hibernate.sql.results.graph.internal.ImmutableFetchList;
/**
* @author Steve Ebersole
@ -55,8 +56,8 @@ public abstract class AbstractNonJoinedEntityFetch implements EntityFetch {
}
@Override
public List<Fetch> getFetches() {
return Collections.emptyList();
public ImmutableFetchList getFetches() {
return ImmutableFetchList.EMPTY;
}
@Override
@ -64,6 +65,16 @@ public abstract class AbstractNonJoinedEntityFetch implements EntityFetch {
return null;
}
@Override
public boolean hasJoinFetches() {
return false;
}
@Override
public boolean containsCollectionFetches() {
return false;
}
@Override
public EntityMappingType getReferencedMappingType() {
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.ScrollableResultsImpl;
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.jdbc.spi.JdbcValuesMapping;
import org.hibernate.sql.results.jdbc.spi.JdbcValues;
@ -74,15 +72,9 @@ public class ScrollableResultsConsumer<R> implements ResultsConsumer<ScrollableR
private boolean containsCollectionFetches(JdbcValuesMapping valuesMapping) {
final List<DomainResult<?>> domainResults = valuesMapping.getDomainResults();
for ( DomainResult domainResult : domainResults ) {
if ( domainResult instanceof EntityResult ) {
EntityResult entityResult = (EntityResult) domainResult;
final List<Fetch> fetches = entityResult.getFetches();
for ( Fetch fetch : fetches ) {
if ( fetch instanceof EagerCollectionFetch ) {
return true;
}
}
for ( DomainResult<?> domainResult : domainResults ) {
if ( domainResult instanceof EntityResult && ( (EntityResult) domainResult ).containsCollectionFetches() ) {
return true;
}
}
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.internal.EntityDelayedFetchImpl;
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.orm.junit.DomainModel;
@ -190,13 +191,12 @@ public class CriteriaEntityGraphTest implements SessionFactoryScopeAware {
Fetchable fetchable = getFetchable( "company", Person.class );
final Fetch companyFetch = ownerEntityResult.findFetch( fetchable );
List<Fetch> fetches = ownerEntityResult.getFetches();
assertThat( companyFetch, notNullValue() );
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, instanceOf( DelayedCollectionFetch.class ) );
} );
@ -348,9 +348,9 @@ public class CriteriaEntityGraphTest implements SessionFactoryScopeAware {
final EntityResult entityResult = (EntityResult) domainResult;
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 ) );
final EntityFetch entityFetch = (EntityFetch) fetch;

View File

@ -189,9 +189,9 @@ public class EntityGraphLoadPlanBuilderTest implements SessionFactoryScopeAware
assertThat( companyFetch, notNullValue() );
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, instanceOf( DelayedCollectionFetch.class ) );
} );
@ -337,9 +337,9 @@ public class EntityGraphLoadPlanBuilderTest implements SessionFactoryScopeAware
final EntityResult entityResult = (EntityResult) domainResult;
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 ) );
final EntityFetch entityFetch = (EntityFetch) fetch;

View File

@ -191,9 +191,9 @@ public class HqlEntityGraphTest implements SessionFactoryScopeAware {
assertThat( companyFetch, notNullValue() );
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, instanceOf( DelayedCollectionFetch.class ) );
} );
@ -345,9 +345,9 @@ public class HqlEntityGraphTest implements SessionFactoryScopeAware {
final EntityResult entityResult = (EntityResult) domainResult;
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 ) );
final EntityFetch entityFetch = (EntityFetch) fetch;

View File

@ -73,12 +73,12 @@ public class LoadPlanBuilderTest {
final EntityResult entityResult = (EntityResult) domainResult;
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.getFetchedMapping().getFetchableName() ).isEqualTo( "msgTxt" );
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.getFetchedMapping().getFetchableName() ).isEqualTo( "poster" );
assertThat( posterFetch.getTiming() ).isEqualTo( FetchTiming.DELAYED );
@ -114,12 +114,12 @@ public class LoadPlanBuilderTest {
final EntityResult entityResult = (EntityResult) domainResult;
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.getFetchedMapping().getFetchableName() ).isEqualTo( "msgTxt" );
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.getFetchedMapping().getFetchableName() ).isEqualTo( "poster" );
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.entity.EntityResult;
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.SessionFactory;
@ -85,22 +86,22 @@ public class MappedFetchTests {
assertThat( domainResult, instanceOf( EntityResult.class ) );
final EntityResult entityResult = (EntityResult) domainResult;
final List<Fetch> fetches = entityResult.getFetches();
final ImmutableFetchList fetches = entityResult.getFetches();
// name + both lists
assertThat( fetches.size(), is( 3 ) );
// 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, 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, 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, instanceOf( DelayedCollectionFetch.class ) );