HHH-16830 Add applyToLoadByKey filters also to to-one join predicates

This commit is contained in:
Christian Beikov 2024-05-27 19:44:51 +02:00
parent be8705f317
commit d22725a678
31 changed files with 370 additions and 174 deletions

View File

@ -58,7 +58,7 @@ public class LoadQueryInfluencers implements Serializable {
private int batchSize = -1;
private final EffectiveEntityGraph effectiveEntityGraph = new EffectiveEntityGraph();
private final EffectiveEntityGraph effectiveEntityGraph;
private Boolean readOnly;
@ -66,12 +66,14 @@ public class LoadQueryInfluencers implements Serializable {
this.sessionFactory = sessionFactory;
batchSize = sessionFactory.getSessionFactoryOptions().getDefaultBatchFetchSize();
subselectFetchEnabled = sessionFactory.getSessionFactoryOptions().isSubselectFetchEnabled();
effectiveEntityGraph = new EffectiveEntityGraph();
}
public LoadQueryInfluencers(SessionFactoryImplementor sessionFactory, SessionCreationOptions options) {
this.sessionFactory = sessionFactory;
batchSize = options.getDefaultBatchFetchSize();
subselectFetchEnabled = options.isSubselectFetchEnabled();
effectiveEntityGraph = new EffectiveEntityGraph();
for (FilterDefinition filterDefinition : sessionFactory.getAutoEnabledFilters()) {
FilterImpl filter = new FilterImpl( filterDefinition );
if ( enabledFilters == null ) {
@ -81,31 +83,6 @@ public class LoadQueryInfluencers implements Serializable {
}
}
/**
* Special constructor for {@link #copyForLoadByKey()}.
*/
private LoadQueryInfluencers(LoadQueryInfluencers original) {
this.sessionFactory = original.sessionFactory;
this.enabledCascadingFetchProfile = original.enabledCascadingFetchProfile;
this.enabledFetchProfileNames = original.enabledFetchProfileNames == null ? null : new HashSet<>( original.enabledFetchProfileNames );
this.subselectFetchEnabled = original.subselectFetchEnabled;
this.batchSize = original.batchSize;
this.readOnly = original.readOnly;
HashMap<String,Filter> enabledFilters;
if ( original.enabledFilters == null ) {
enabledFilters = null;
}
else {
enabledFilters = new HashMap<>( original.enabledFilters.size() );
for ( Map.Entry<String, Filter> entry : original.enabledFilters.entrySet() ) {
if ( entry.getValue().isApplyToLoadByKey() ) {
enabledFilters.put( entry.getKey(), entry.getValue() );
}
}
}
this.enabledFilters = enabledFilters;
}
public EffectiveEntityGraph applyEntityGraph(@Nullable RootGraphImplementor<?> rootGraph, @Nullable GraphSemantic graphSemantic) {
final EffectiveEntityGraph effectiveEntityGraph = getEffectiveEntityGraph();
if ( graphSemantic != null ) {
@ -407,8 +384,4 @@ public class LoadQueryInfluencers implements Serializable {
}
return false;
}
public LoadQueryInfluencers copyForLoadByKey() {
return new LoadQueryInfluencers( this );
}
}

View File

@ -128,18 +128,13 @@ public class FilterHelper {
}
public boolean isAffectedBy(Map<String, Filter> enabledFilters) {
for ( String filterName : filterNames ) {
if ( enabledFilters.containsKey( filterName ) ) {
return true;
}
}
return false;
return isAffectedBy( enabledFilters, false );
}
public boolean isAffectedByApplyToLoadByKey(Map<String, Filter> enabledFilters) {
public boolean isAffectedBy(Map<String, Filter> enabledFilters, boolean onlyApplyForLoadByKey) {
for ( String filterName : filterNames ) {
Filter filter = enabledFilters.get( filterName );
if ( filter != null && filter.isApplyToLoadByKey() ) {
if ( filter != null && ( !onlyApplyForLoadByKey || filter.isApplyToLoadByKey() ) ) {
return true;
}
}
@ -158,6 +153,7 @@ public class FilterHelper {
rootTableGroup,
useIdentificationVariable,
loadQueryInfluencers.getEnabledFilters(),
astCreationState.applyOnlyLoadByKeyFilters(),
null,
astCreationState
);
@ -167,11 +163,13 @@ public class FilterHelper {
Consumer<Predicate> predicateConsumer,
FilterAliasGenerator aliasGenerator,
Map<String, Filter> enabledFilters,
boolean onlyApplyLoadByKeyFilters,
TableGroup tableGroup,
SqlAstCreationState creationState) {
final FilterPredicate predicate = generateFilterPredicate(
aliasGenerator,
enabledFilters,
onlyApplyLoadByKeyFilters,
tableGroup,
creationState
);
@ -183,6 +181,7 @@ public class FilterHelper {
private FilterPredicate generateFilterPredicate(
FilterAliasGenerator aliasGenerator,
Map<String, Filter> enabledFilters,
boolean onlyApplyLoadByKeyFilters,
TableGroup tableGroup,
SqlAstCreationState creationState) {
final FilterPredicate filterPredicate = new FilterPredicate();
@ -190,7 +189,7 @@ public class FilterHelper {
for ( int i = 0, max = filterNames.length; i < max; i++ ) {
final String filterName = filterNames[i];
final FilterImpl enabledFilter = (FilterImpl) enabledFilters.get( filterName );
if ( enabledFilter != null ) {
if ( enabledFilter != null && ( !onlyApplyLoadByKeyFilters || enabledFilter.isApplyToLoadByKey() ) ) {
filterPredicate.applyFragment( render( aliasGenerator, i, tableGroup, creationState ), enabledFilter, parameterNames[i] );
}
}

View File

@ -686,27 +686,26 @@ public class LoaderSelectBuilder {
TableGroup tableGroup,
PluralAttributeMapping pluralAttributeMapping,
SqlAstCreationState astCreationState) {
final NavigablePath parentNavigablePath = tableGroup.getNavigablePath().getParent();
if ( parentNavigablePath == null ) {
// Only apply restrictions for root table groups,
// because for table group joins the restriction is applied via PluralAttributeMappingImpl.createTableGroupJoin
pluralAttributeMapping.applyBaseRestrictions(
querySpec::applyPredicate,
tableGroup,
true,
loadQueryInfluencers.getEnabledFilters(),
null,
astCreationState
);
pluralAttributeMapping.applyBaseManyToManyRestrictions(
querySpec::applyPredicate,
tableGroup,
true,
loadQueryInfluencers.getEnabledFilters(),
null,
astCreationState
);
}
// Only apply restrictions for root table groups,
// because for table group joins the restriction is applied via PluralAttributeMappingImpl.createTableGroupJoin
assert tableGroup.getNavigablePath().getParent() == null;
pluralAttributeMapping.applyBaseRestrictions(
querySpec::applyPredicate,
tableGroup,
true,
loadQueryInfluencers.getEnabledFilters(),
false,
null,
astCreationState
);
pluralAttributeMapping.applyBaseManyToManyRestrictions(
querySpec::applyPredicate,
tableGroup,
true,
loadQueryInfluencers.getEnabledFilters(),
null,
astCreationState
);
}
private void applyFiltering(
@ -719,6 +718,7 @@ public class LoaderSelectBuilder {
tableGroup,
true,
loadQueryInfluencers.getEnabledFilters(),
true,
null,
astCreationState
);
@ -966,15 +966,7 @@ public class LoaderSelectBuilder {
if ( fetch.getTiming() == FetchTiming.IMMEDIATE && joined ) {
if ( isFetchablePluralAttributeMapping ) {
final PluralAttributeMapping pluralAttributeMapping = (PluralAttributeMapping) fetchable;
final TableGroup joinTableGroup = creationState.getFromClauseAccess()
.getTableGroup( fetchablePath );
final QuerySpec querySpec = creationState.getInflightQueryPart().getFirstQuerySpec();
applyFiltering(
querySpec,
joinTableGroup,
pluralAttributeMapping,
creationState
);
applyOrdering(
querySpec,
fetchablePath,
@ -982,19 +974,6 @@ public class LoaderSelectBuilder {
creationState
);
}
else if ( fetchable instanceof ToOneAttributeMapping ) {
final EntityMappingType entityType = ( (ToOneAttributeMapping) fetchable ).getEntityMappingType();
final FromClauseAccess fromClauseAccess = creationState.getFromClauseAccess();
final TableGroup joinTableGroup = fromClauseAccess.getTableGroup( fetchablePath );
final TableGroupJoin join = fromClauseAccess.getTableGroup( fetchParent.getNavigablePath() )
.findTableGroupJoin( joinTableGroup );
applyFiltering(
join,
joinTableGroup,
entityType,
creationState
);
}
}
fetches.add( fetch );

View File

@ -154,6 +154,11 @@ public class LoaderSqlAstCreationState
return loadQueryInfluencers;
}
@Override
public boolean applyOnlyLoadByKeyFilters() {
return true;
}
@Override
public void registerLockMode(String identificationVariable, LockMode explicitLockMode) {
throw new UnsupportedOperationException( "Registering lock modes should only be done for result set mappings" );

View File

@ -219,7 +219,7 @@ public class MultiIdEntityLoaderStandard<T> extends AbstractMultiIdEntityLoader<
getLoadable().getIdentifierMapping(),
null,
numberOfIdsInBatch,
session.getLoadQueryInfluencers().copyForLoadByKey(),
session.getLoadQueryInfluencers(),
lockOptions,
jdbcParametersBuilder::add,
getSessionFactory()

View File

@ -95,7 +95,7 @@ public class SingleIdEntityLoaderStandardImpl<T> extends SingleIdEntityLoaderSup
LoadQueryInfluencers loadQueryInfluencers,
SessionFactoryImplementor sessionFactory) {
if ( getLoadable().isAffectedByEnabledFilters( loadQueryInfluencers ) ) {
if ( getLoadable().isAffectedByEnabledFilters( loadQueryInfluencers, true ) ) {
// This case is special because the filters need to be applied in order to
// properly restrict the SQL/JDBC results. For this reason it has higher
// precedence than even "internal" fetch profiles.

View File

@ -28,17 +28,18 @@ public interface Loadable extends ModelPart, RootTableGroupProducer {
*/
String getRootPathName();
/**
* @deprecated Use {@link #isAffectedByInfluencers(LoadQueryInfluencers, boolean)} instead
*/
@Deprecated(forRemoval = true)
default boolean isAffectedByInfluencers(LoadQueryInfluencers influencers) {
return isAffectedByEntityGraph( influencers )
|| isAffectedByEnabledFetchProfiles( influencers )
|| isAffectedByEnabledFilters( influencers )
|| isAffectedByBatchSize( influencers );
return isAffectedByInfluencers( influencers, false );
}
default boolean isAffectedByInfluencersForLoadByKey(LoadQueryInfluencers influencers) {
default boolean isAffectedByInfluencers(LoadQueryInfluencers influencers, boolean onlyApplyForLoadByKeyFilters) {
return isAffectedByEntityGraph( influencers )
|| isAffectedByEnabledFetchProfiles( influencers )
|| isAffectedByEnabledFiltersForLoadByKey( influencers )
|| isAffectedByEnabledFilters( influencers, onlyApplyForLoadByKeyFilters )
|| isAffectedByBatchSize( influencers );
}
@ -59,15 +60,17 @@ public interface Loadable extends ModelPart, RootTableGroupProducer {
/**
* Whether any of the "influencers" affect this loadable.
* @deprecated Use {@link #isAffectedByEnabledFilters(LoadQueryInfluencers, boolean)} instead
*/
boolean isAffectedByEnabledFilters(LoadQueryInfluencers influencers);
@Deprecated(forRemoval = true)
default boolean isAffectedByEnabledFilters(LoadQueryInfluencers influencers) {
return isAffectedByEnabledFilters( influencers, false );
}
/**
* Whether any of the "influencers" affect this loadable.
*/
default boolean isAffectedByEnabledFiltersForLoadByKey(LoadQueryInfluencers influencers) {
return isAffectedByInfluencers( influencers.copyForLoadByKey() );
}
boolean isAffectedByEnabledFilters(LoadQueryInfluencers influencers, boolean onlyApplyForLoadByKeyFilters);
/**
* Whether the {@linkplain LoadQueryInfluencers#getEffectiveEntityGraph() effective entity-graph}

View File

@ -543,13 +543,8 @@ public interface EntityMappingType
// Loadable
@Override
default boolean isAffectedByEnabledFilters(LoadQueryInfluencers influencers) {
return getEntityPersister().isAffectedByEnabledFilters( influencers );
}
@Override
default boolean isAffectedByEnabledFiltersForLoadByKey(LoadQueryInfluencers influencers) {
return getEntityPersister().isAffectedByEnabledFiltersForLoadByKey( influencers );
default boolean isAffectedByEnabledFilters(LoadQueryInfluencers influencers, boolean onlyApplyForLoadByKeyFilters) {
return getEntityPersister().isAffectedByEnabledFilters( influencers, onlyApplyForLoadByKeyFilters );
}
@Override
@ -651,8 +646,16 @@ public interface EntityMappingType
TableGroup tableGroup,
boolean useQualifier,
Map<String, Filter> enabledFilters,
boolean onlyApplyLoadByKeyFilters,
SqlAstCreationState creationState) {
getEntityPersister().applyFilterRestrictions( predicateConsumer, tableGroup, useQualifier, enabledFilters, creationState );
getEntityPersister().applyFilterRestrictions(
predicateConsumer,
tableGroup,
useQualifier,
enabledFilters,
onlyApplyLoadByKeyFilters,
creationState
);
}
@Override
@ -661,9 +664,18 @@ public interface EntityMappingType
TableGroup tableGroup,
boolean useQualifier,
Map<String, Filter> enabledFilters,
boolean onlyApplyLoadByKeyFilters,
Set<String> treatAsDeclarations,
SqlAstCreationState creationState) {
getEntityPersister().applyBaseRestrictions( predicateConsumer, tableGroup, useQualifier, enabledFilters, treatAsDeclarations, creationState );
getEntityPersister().applyBaseRestrictions(
predicateConsumer,
tableGroup,
useQualifier,
enabledFilters,
onlyApplyLoadByKeyFilters,
treatAsDeclarations,
creationState
);
}
@Override

View File

@ -21,6 +21,21 @@ import org.hibernate.sql.ast.tree.predicate.Predicate;
*/
public interface FilterRestrictable {
/**
* Applies just the {@link org.hibernate.annotations.Filter}
* values enabled for the associated entity
* @deprecated Use {@link #applyFilterRestrictions(Consumer, TableGroup, boolean, Map, boolean, SqlAstCreationState)} instead
*/
@Deprecated(forRemoval = true)
default void applyFilterRestrictions(
Consumer<Predicate> predicateConsumer,
TableGroup tableGroup,
boolean useQualifier,
Map<String, Filter> enabledFilters,
SqlAstCreationState creationState) {
applyFilterRestrictions( predicateConsumer, tableGroup, useQualifier, enabledFilters, false, creationState );
}
/**
* Applies just the {@link org.hibernate.annotations.Filter}
* values enabled for the associated entity
@ -30,5 +45,6 @@ public interface FilterRestrictable {
TableGroup tableGroup,
boolean useQualifier,
Map<String, Filter> enabledFilters,
boolean onlyApplyLoadByKeyFilters,
SqlAstCreationState creationState);
}

View File

@ -6,9 +6,16 @@
*/
package org.hibernate.metamodel.mapping;
import java.util.Set;
import java.util.function.Consumer;
import org.hibernate.engine.FetchStyle;
import org.hibernate.engine.FetchTiming;
import org.hibernate.engine.spi.LoadQueryInfluencers;
import org.hibernate.internal.util.IndexedConsumer;
import org.hibernate.metamodel.mapping.internal.ToOneAttributeMapping;
import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.sql.results.graph.FetchOptions;
import org.hibernate.sql.results.graph.FetchableContainer;
import org.hibernate.type.descriptor.java.JavaType;
@ -112,4 +119,35 @@ public interface ManagedMappingType extends MappingType, FetchableContainer {
}
return false;
}
default boolean isAffectedByEnabledFilters(
Set<ManagedMappingType> visitedTypes,
LoadQueryInfluencers influencers,
boolean onlyApplyForLoadByKey) {
if ( !visitedTypes.add( this ) ) {
return false;
}
// we still need to verify collection fields to be eagerly loaded by join
final AttributeMappingsList attributeMappings = getAttributeMappings();
for ( int i = 0; i < attributeMappings.size(); i++ ) {
final AttributeMapping attributeMapping = attributeMappings.get( i );
final FetchOptions mappedFetchOptions = attributeMapping.getMappedFetchOptions();
if ( mappedFetchOptions.getTiming() == FetchTiming.IMMEDIATE
&& mappedFetchOptions.getStyle() == FetchStyle.JOIN ) {
if ( attributeMapping instanceof PluralAttributeMapping ) {
final CollectionPersister collectionDescriptor = ( (PluralAttributeMapping) attributeMapping ).getCollectionDescriptor();
if ( collectionDescriptor.isAffectedByEnabledFilters( visitedTypes, influencers, onlyApplyForLoadByKey ) ) {
return true;
}
}
else if ( attributeMapping instanceof ToOneAttributeMapping ) {
final EntityMappingType entityMappingType = ( (ToOneAttributeMapping) attributeMapping ).getEntityMappingType();
if ( entityMappingType.isAffectedByEnabledFilters( visitedTypes, influencers, onlyApplyForLoadByKey ) ) {
return true;
}
}
}
}
return false;
}
}

View File

@ -156,8 +156,16 @@ public interface PluralAttributeMapping
TableGroup tableGroup,
boolean useQualifier,
Map<String, Filter> enabledFilters,
boolean onlyApplyLoadByKeyFilters,
SqlAstCreationState creationState) {
getCollectionDescriptor().applyFilterRestrictions( predicateConsumer, tableGroup, useQualifier, enabledFilters, creationState );
getCollectionDescriptor().applyFilterRestrictions(
predicateConsumer,
tableGroup,
useQualifier,
enabledFilters,
onlyApplyLoadByKeyFilters,
creationState
);
}
@Override
@ -166,9 +174,18 @@ public interface PluralAttributeMapping
TableGroup tableGroup,
boolean useQualifier,
Map<String, Filter> enabledFilters,
boolean onlyApplyLoadByKeyFilters,
Set<String> treatAsDeclarations,
SqlAstCreationState creationState) {
getCollectionDescriptor().applyBaseRestrictions( predicateConsumer, tableGroup, useQualifier, enabledFilters, treatAsDeclarations, creationState );
getCollectionDescriptor().applyBaseRestrictions(
predicateConsumer,
tableGroup,
useQualifier,
enabledFilters,
onlyApplyLoadByKeyFilters,
treatAsDeclarations,
creationState
);
}
default void applyBaseManyToManyRestrictions(

View File

@ -22,6 +22,29 @@ import org.hibernate.sql.ast.tree.predicate.Predicate;
* {@linkplain PluralAttributeMapping plural attributes}.
*/
public interface Restrictable extends FilterRestrictable, WhereRestrictable {
/**
* Applies the base set of restrictions.
* @deprecated Use {@link #applyBaseRestrictions(Consumer, TableGroup, boolean, Map, boolean, Set, SqlAstCreationState)} instead
*/
@Deprecated(forRemoval = true)
default void applyBaseRestrictions(
Consumer<Predicate> predicateConsumer,
TableGroup tableGroup,
boolean useQualifier,
Map<String, Filter> enabledFilters,
Set<String> treatAsDeclarations,
SqlAstCreationState creationState) {
applyBaseRestrictions(
predicateConsumer,
tableGroup,
useQualifier,
enabledFilters,
false,
treatAsDeclarations,
creationState
);
}
/**
* Applies the base set of restrictions.
*/
@ -30,6 +53,7 @@ public interface Restrictable extends FilterRestrictable, WhereRestrictable {
TableGroup tableGroup,
boolean useQualifier,
Map<String, Filter> enabledFilters,
boolean onlyApplyLoadByKeyFilters,
Set<String> treatAsDeclarations,
SqlAstCreationState creationState);
}
}

View File

@ -740,6 +740,7 @@ public class PluralAttributeMappingImpl
tableGroup,
true,
creationState.getLoadQueryInfluencers().getEnabledFilters(),
false,
null,
creationState
);
@ -1002,7 +1003,7 @@ public class PluralAttributeMappingImpl
final boolean nestedJoin = joinType != SqlAstJoinType.INNER
// For outer joins we need nesting if there might be an on-condition that refers to the element table
&& ( addsPredicate
|| isAffectedByEnabledFilters( creationState.getLoadQueryInfluencers() )
|| isAffectedByEnabledFilters( creationState.getLoadQueryInfluencers(), creationState.applyOnlyLoadByKeyFilters() )
|| collectionDescriptor.hasWhereRestrictions() );
if ( elementDescriptor instanceof TableGroupJoinProducer ) {
@ -1073,13 +1074,8 @@ public class PluralAttributeMappingImpl
}
@Override
public boolean isAffectedByEnabledFilters(LoadQueryInfluencers influencers) {
return getCollectionDescriptor().isAffectedByEnabledFilters( influencers );
}
@Override
public boolean isAffectedByEnabledFiltersForLoadByKey(LoadQueryInfluencers influencers) {
return getCollectionDescriptor().isAffectedByEnabledFiltersForLoadByKey( influencers );
public boolean isAffectedByEnabledFilters(LoadQueryInfluencers influencers, boolean onlyApplyForLoadByKeyFilters) {
return getCollectionDescriptor().isAffectedByEnabledFilters( influencers, onlyApplyForLoadByKeyFilters );
}
@Override

View File

@ -2088,7 +2088,19 @@ public class ToOneAttributeMapping
creationState
) );
// Note specifically we DO NOT apply `@Filter` restrictions
// Note specifically we only apply `@Filter` restrictions that are applyToLoadByKey = true
// to make the behavior consistent with lazy loading of an association
if ( getAssociatedEntityMappingType().getEntityPersister().hasFilterForLoadByKey() ) {
getAssociatedEntityMappingType().applyBaseRestrictions(
join::applyPredicate,
tableGroup,
true,
creationState.getLoadQueryInfluencers().getEnabledFilters(),
creationState.applyOnlyLoadByKeyFilters(),
null,
creationState
);
}
getAssociatedEntityMappingType().applyWhereRestrictions(
join::applyPredicate,
tableGroup,

View File

@ -79,9 +79,14 @@ import org.hibernate.mapping.Table;
import org.hibernate.mapping.Value;
import org.hibernate.metadata.CollectionMetadata;
import org.hibernate.metamodel.CollectionClassification;
import org.hibernate.metamodel.mapping.CollectionPart;
import org.hibernate.metamodel.mapping.EmbeddableMappingType;
import org.hibernate.metamodel.mapping.EmbeddableValuedModelPart;
import org.hibernate.metamodel.mapping.ForeignKeyDescriptor;
import org.hibernate.metamodel.mapping.ManagedMappingType;
import org.hibernate.metamodel.mapping.PluralAttributeMapping;
import org.hibernate.metamodel.mapping.internal.EmbeddedCollectionPart;
import org.hibernate.metamodel.mapping.internal.EntityCollectionPart;
import org.hibernate.metamodel.mapping.internal.MappingModelCreationHelper;
import org.hibernate.metamodel.mapping.internal.PluralAttributeMappingImpl;
import org.hibernate.metamodel.model.domain.NavigableRole;
@ -681,7 +686,7 @@ public abstract class AbstractCollectionPersister
collectionLoader = createNamedQueryCollectionLoader( this, getNamedQueryMemento( null ) );
}
else {
collectionLoader = createNamedQueryCollectionLoader( new LoadQueryInfluencers( factory ) );
collectionLoader = createCollectionLoader( new LoadQueryInfluencers( factory ) );
}
if ( attributeMapping.getIndexDescriptor() != null ) {
@ -784,8 +789,8 @@ public abstract class AbstractCollectionPersister
}
}
return attributeMapping.isAffectedByInfluencers( influencers )
? createNamedQueryCollectionLoader( influencers )
return attributeMapping.isAffectedByInfluencers( influencers, true )
? createCollectionLoader( influencers )
: getCollectionLoader();
}
@ -830,7 +835,7 @@ public abstract class AbstractCollectionPersister
// return attributeMapping.isNotAffectedByInfluencers( loadQueryInfluencers );
// }
private CollectionLoader createNamedQueryCollectionLoader(LoadQueryInfluencers loadQueryInfluencers) {
private CollectionLoader createCollectionLoader(LoadQueryInfluencers loadQueryInfluencers) {
if ( loadQueryInfluencers.effectivelyBatchLoadable( this ) ) {
final int batchSize = loadQueryInfluencers.effectiveBatchSize( this );
return factory.getServiceRegistry()
@ -1218,8 +1223,34 @@ public abstract class AbstractCollectionPersister
}
@Override
public void applyBaseRestrictions(Consumer<Predicate> predicateConsumer, TableGroup tableGroup, boolean useQualifier, Map<String, Filter> enabledFilters, Set<String> treatAsDeclarations, SqlAstCreationState creationState) {
applyFilterRestrictions( predicateConsumer, tableGroup, useQualifier, enabledFilters, creationState );
public void applyBaseRestrictions(
Consumer<Predicate> predicateConsumer,
TableGroup tableGroup,
boolean useQualifier,
Map<String, Filter> enabledFilters,
Set<String> treatAsDeclarations,
SqlAstCreationState creationState) {
applyBaseRestrictions(
predicateConsumer,
tableGroup,
useQualifier,
enabledFilters,
false,
treatAsDeclarations,
creationState
);
}
@Override
public void applyBaseRestrictions(
Consumer<Predicate> predicateConsumer,
TableGroup tableGroup,
boolean useQualifier,
Map<String, Filter> enabledFilters,
boolean onlyApplyLoadByKeyFilters,
Set<String> treatAsDeclarations,
SqlAstCreationState creationState) {
applyFilterRestrictions( predicateConsumer, tableGroup, useQualifier, enabledFilters, onlyApplyLoadByKeyFilters, creationState );
applyWhereRestrictions( predicateConsumer, tableGroup, useQualifier, creationState );
}
@ -1289,12 +1320,14 @@ public abstract class AbstractCollectionPersister
TableGroup tableGroup,
boolean useQualifier,
Map<String, Filter> enabledFilters,
boolean onlyApplyLoadByKeyFilters,
SqlAstCreationState creationState) {
if ( filterHelper != null ) {
filterHelper.applyEnabledFilters(
predicateConsumer,
getFilterAliasGenerator( tableGroup ),
enabledFilters,
onlyApplyLoadByKeyFilters,
tableGroup,
creationState
);
@ -1323,6 +1356,7 @@ public abstract class AbstractCollectionPersister
predicateConsumer,
aliasGenerator,
enabledFilters,
false,
tableGroup,
creationState
);
@ -1594,6 +1628,10 @@ public abstract class AbstractCollectionPersister
@Override
public Object getElementByIndex(Object key, Object index, SharedSessionContractImplementor session, Object owner) {
if ( isAffectedByFilters( new HashSet<>(), attributeMapping.getElementDescriptor(), session.getLoadQueryInfluencers(), true ) ) {
return new CollectionElementLoaderByIndex( attributeMapping, session.getLoadQueryInfluencers(), factory )
.load( key, index, session );
}
return collectionElementLoaderByIndex.load( key, index, session );
}
@ -1667,10 +1705,16 @@ public abstract class AbstractCollectionPersister
@Override
public boolean isAffectedByEnabledFilters(LoadQueryInfluencers influencers) {
return isAffectedByEnabledFilters( influencers, false );
}
@Override
public boolean isAffectedByEnabledFilters(LoadQueryInfluencers influencers, boolean onlyApplyForLoadByKeyFilters) {
if ( influencers.hasEnabledFilters() ) {
final Map<String, Filter> enabledFilters = influencers.getEnabledFilters();
return filterHelper != null && filterHelper.isAffectedBy( enabledFilters )
|| manyToManyFilterHelper != null && manyToManyFilterHelper.isAffectedBy( enabledFilters );
|| manyToManyFilterHelper != null && manyToManyFilterHelper.isAffectedBy( enabledFilters )
|| isKeyOrElementAffectedByFilters( new HashSet<>(), influencers, onlyApplyForLoadByKeyFilters);
}
else {
return false;
@ -1678,17 +1722,45 @@ public abstract class AbstractCollectionPersister
}
@Override
public boolean isAffectedByEnabledFiltersForLoadByKey(LoadQueryInfluencers influencers) {
public boolean isAffectedByEnabledFilters(
Set<ManagedMappingType> visitedTypes,
LoadQueryInfluencers influencers,
boolean onlyApplyForLoadByKeyFilters) {
if ( influencers.hasEnabledFilters() ) {
final Map<String, Filter> enabledFilters = influencers.getEnabledFilters();
return filterHelper != null && filterHelper.isAffectedByApplyToLoadByKey( enabledFilters )
|| manyToManyFilterHelper != null && manyToManyFilterHelper.isAffectedByApplyToLoadByKey( enabledFilters );
return filterHelper != null && filterHelper.isAffectedBy( enabledFilters )
|| manyToManyFilterHelper != null && manyToManyFilterHelper.isAffectedBy( enabledFilters )
|| isKeyOrElementAffectedByFilters( visitedTypes, influencers, onlyApplyForLoadByKeyFilters);
}
else {
return false;
}
}
private boolean isKeyOrElementAffectedByFilters(
Set<ManagedMappingType> visitedTypes,
LoadQueryInfluencers influencers,
boolean onlyApplyForLoadByKey) {
return isAffectedByFilters( visitedTypes, attributeMapping.getIndexDescriptor(), influencers, onlyApplyForLoadByKey )
|| isAffectedByFilters( visitedTypes, attributeMapping.getElementDescriptor(), influencers, onlyApplyForLoadByKey );
}
private boolean isAffectedByFilters(
Set<ManagedMappingType> visitedTypes,
CollectionPart collectionPart,
LoadQueryInfluencers influencers,
boolean onlyApplyForLoadByKey) {
if ( collectionPart instanceof EntityCollectionPart ) {
return ( (EntityCollectionPart) collectionPart ).getEntityMappingType()
.isAffectedByEnabledFilters( visitedTypes, influencers, onlyApplyForLoadByKey );
}
else if ( collectionPart instanceof EmbeddedCollectionPart ) {
final EmbeddableMappingType type = ( (EmbeddedCollectionPart) collectionPart ).getEmbeddableTypeDescriptor();
return type.isAffectedByEnabledFilters( visitedTypes, influencers, onlyApplyForLoadByKey );
}
return false;
}
@Override
public boolean isAffectedByEntityGraph(LoadQueryInfluencers influencers) {
// todo (6.0) : anything to do here?

View File

@ -25,6 +25,7 @@ import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.id.IdentifierGenerator;
import org.hibernate.metadata.CollectionMetadata;
import org.hibernate.metamodel.CollectionClassification;
import org.hibernate.metamodel.mapping.ManagedMappingType;
import org.hibernate.metamodel.mapping.PluralAttributeMapping;
import org.hibernate.metamodel.mapping.Restrictable;
import org.hibernate.metamodel.model.domain.NavigableRole;
@ -296,7 +297,14 @@ public interface CollectionPersister extends Restrictable {
throw new UnsupportedOperationException( "CollectionPersister used for [" + getRole() + "] does not support SQL AST" );
}
default boolean isAffectedByEnabledFiltersForLoadByKey(LoadQueryInfluencers influencers) {
default boolean isAffectedByEnabledFilters(LoadQueryInfluencers influencers, boolean onlyApplyForLoadByKeyFilters) {
throw new UnsupportedOperationException( "CollectionPersister used for [" + getRole() + "] does not support SQL AST" );
}
default boolean isAffectedByEnabledFilters(
Set<ManagedMappingType> visitedTypes,
LoadQueryInfluencers influencers,
boolean onlyApplyForLoadByKey) {
throw new UnsupportedOperationException( "CollectionPersister used for [" + getRole() + "] does not support SQL AST" );
}

View File

@ -280,6 +280,7 @@ import org.hibernate.sql.model.ast.builder.TableInsertBuilder;
import org.hibernate.sql.results.graph.DomainResult;
import org.hibernate.sql.results.graph.DomainResultCreationState;
import org.hibernate.sql.results.graph.Fetch;
import org.hibernate.sql.results.graph.FetchOptions;
import org.hibernate.sql.results.graph.FetchParent;
import org.hibernate.sql.results.graph.Fetchable;
import org.hibernate.sql.results.graph.FetchableContainer;
@ -2673,11 +2674,11 @@ public abstract class AbstractEntityPersister
final SingularAttributeMapping attribute = (SingularAttributeMapping) findByPath( attributeName );
final LoadQueryInfluencers influencers = session.getLoadQueryInfluencers();
// no subselect fetching for entities for now
if ( isAffectedByInfluencersForLoadByKey( influencers ) ) {
if ( isAffectedByInfluencers( influencers, true ) ) {
return new SingleUniqueKeyEntityLoaderStandard<>(
this,
attribute,
influencers.copyForLoadByKey()
influencers
);
}
final SingleUniqueKeyEntityLoader<?> existing;
@ -3291,6 +3292,7 @@ public abstract class AbstractEntityPersister
TableGroup tableGroup,
boolean useQualifier,
Map<String, Filter> enabledFilters,
boolean onlyApplyLoadByKeyFilters,
SqlAstCreationState creationState) {
if ( filterHelper != null ) {
final FilterAliasGenerator filterAliasGenerator = useQualifier && tableGroup != null
@ -3300,6 +3302,7 @@ public abstract class AbstractEntityPersister
predicateConsumer,
filterAliasGenerator,
enabledFilters,
onlyApplyLoadByKeyFilters,
tableGroup,
creationState
);
@ -3311,9 +3314,17 @@ public abstract class AbstractEntityPersister
Consumer<Predicate> predicateConsumer,
TableGroup tableGroup, boolean useQualifier,
Map<String, Filter> enabledFilters,
boolean onlyApplyLoadByKeyFilters,
Set<String> treatAsDeclarations,
SqlAstCreationState creationState) {
applyFilterRestrictions( predicateConsumer, tableGroup, useQualifier, enabledFilters, creationState );
applyFilterRestrictions(
predicateConsumer,
tableGroup,
useQualifier,
enabledFilters,
onlyApplyLoadByKeyFilters,
creationState
);
applyWhereRestrictions( predicateConsumer, tableGroup, useQualifier, creationState );
}
@ -3765,8 +3776,8 @@ public abstract class AbstractEntityPersister
else {
final LoadQueryInfluencers influencers = session.getLoadQueryInfluencers();
// no subselect fetching for entities for now
return isAffectedByInfluencersForLoadByKey( influencers )
? buildSingleIdEntityLoader( influencers.copyForLoadByKey() )
return isAffectedByInfluencers( influencers, true )
? buildSingleIdEntityLoader( influencers )
: getSingleIdLoader();
}
}
@ -3861,49 +3872,15 @@ public abstract class AbstractEntityPersister
}
@Override
public boolean isAffectedByEnabledFilters(LoadQueryInfluencers loadQueryInfluencers) {
public boolean isAffectedByEnabledFilters(
LoadQueryInfluencers loadQueryInfluencers,
boolean onlyApplyForLoadByKeyFilters) {
if ( filterHelper != null && loadQueryInfluencers.hasEnabledFilters() ) {
if ( filterHelper.isAffectedBy( loadQueryInfluencers.getEnabledFilters() ) ) {
if ( filterHelper.isAffectedBy( loadQueryInfluencers.getEnabledFilters(), onlyApplyForLoadByKeyFilters ) ) {
return true;
}
// we still need to verify collection fields to be eagerly loaded by join
final AttributeMappingsList attributeMappings = getAttributeMappings();
for ( int i = 0; i < attributeMappings.size(); i++ ) {
final AttributeMapping attributeMapping = attributeMappings.get( i );
if ( attributeMapping instanceof PluralAttributeMapping ) {
final PluralAttributeMapping pluralAttributeMapping = (PluralAttributeMapping) attributeMapping;
if ( pluralAttributeMapping.getMappedFetchOptions().getTiming() == FetchTiming.IMMEDIATE
&& pluralAttributeMapping.getMappedFetchOptions().getStyle() == FetchStyle.JOIN
&& pluralAttributeMapping.getCollectionDescriptor().isAffectedByEnabledFilters( loadQueryInfluencers ) ) {
return true;
}
}
}
}
return false;
}
@Override
public boolean isAffectedByEnabledFiltersForLoadByKey(LoadQueryInfluencers loadQueryInfluencers) {
if ( filterHelper != null && loadQueryInfluencers.hasEnabledFilters() ) {
if ( filterHelper.isAffectedByApplyToLoadByKey( loadQueryInfluencers.getEnabledFilters() ) ) {
return true;
}
// we still need to verify collection fields to be eagerly loaded by join
final AttributeMappingsList attributeMappings = getAttributeMappings();
for ( int i = 0; i < attributeMappings.size(); i++ ) {
final AttributeMapping attributeMapping = attributeMappings.get( i );
if ( attributeMapping instanceof PluralAttributeMapping ) {
final PluralAttributeMapping pluralAttributeMapping = (PluralAttributeMapping) attributeMapping;
if ( pluralAttributeMapping.getMappedFetchOptions().getTiming() == FetchTiming.IMMEDIATE
&& pluralAttributeMapping.getMappedFetchOptions().getStyle() == FetchStyle.JOIN
&& pluralAttributeMapping.getCollectionDescriptor().isAffectedByEnabledFiltersForLoadByKey( loadQueryInfluencers ) ) {
return true;
}
}
}
return isAffectedByEnabledFilters( new HashSet<>(), loadQueryInfluencers, onlyApplyForLoadByKeyFilters );
}
return false;
}

View File

@ -746,6 +746,11 @@ public class AnonymousTupleEntityValuedModelPart
return false;
}
@Override
public boolean isAffectedByEnabledFilters(LoadQueryInfluencers influencers, boolean onlyApplyForLoadByKeyFilters) {
return false;
}
@Override
public boolean isNotAffectedByInfluencers(LoadQueryInfluencers influencers) {
return true;

View File

@ -251,6 +251,10 @@ public class DomainResultCreationStateImpl
return loadQueryInfluencers;
}
@Override
public boolean applyOnlyLoadByKeyFilters() {
return true;
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// SqlAstProcessingState

View File

@ -137,6 +137,7 @@ public class SimpleDeleteQueryPlan implements NonSelectQueryPlan {
collectionTableGroup,
factory.getJdbcServices().getDialect().getDmlTargetColumnQualifierSupport() == DmlTargetColumnQualifierSupport.TABLE_ALIAS,
executionContext.getSession().getLoadQueryInfluencers().getEnabledFilters(),
false,
null,
null
);

View File

@ -125,6 +125,7 @@ public class MatchingIdSelectionHelper {
mutatingTableGroup,
true,
executionContext.getSession().getLoadQueryInfluencers().getEnabledFilters(),
false,
null,
sqmConverter
);

View File

@ -116,6 +116,7 @@ public class RestrictedDeleteExecutionDelegate extends AbstractDeleteExecutionDe
deletingTableGroup,
true,
executionContext.getSession().getLoadQueryInfluencers().getEnabledFilters(),
false,
null,
getConverter()
);

View File

@ -117,6 +117,7 @@ public class SoftDeleteExecutionDelegate extends AbstractDeleteExecutionDelegate
deletingTableGroup,
true,
executionContext.getSession().getLoadQueryInfluencers().getEnabledFilters(),
false,
null,
getConverter()
);

View File

@ -151,6 +151,7 @@ public class TableBasedUpdateHandler
updatingTableGroup,
true,
executionContext.getSession().getLoadQueryInfluencers().getEnabledFilters(),
false,
null,
converterDelegate
);

View File

@ -756,6 +756,11 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
return loadQueryInfluencers;
}
@Override
public boolean applyOnlyLoadByKeyFilters() {
return false;
}
public FromClauseIndex getFromClauseIndex() {
return (FromClauseIndex) getFromClauseAccess();
}
@ -2818,6 +2823,7 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
tableGroup,
true,
getLoadQueryInfluencers().getEnabledFilters(),
false,
null,
this
);
@ -3511,6 +3517,7 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
tableGroup,
true,
getLoadQueryInfluencers().getEnabledFilters(),
false,
null,
this
);
@ -4656,6 +4663,7 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
tableGroup,
true,
getLoadQueryInfluencers().getEnabledFilters(),
false,
null,
this
);
@ -4810,6 +4818,7 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
tableGroup,
true,
getLoadQueryInfluencers().getEnabledFilters(),
false,
null,
this
);
@ -4954,6 +4963,7 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
tableGroup,
true,
getLoadQueryInfluencers().getEnabledFilters(),
false,
null,
this
);
@ -7695,6 +7705,7 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
tableGroup,
true,
getLoadQueryInfluencers().getEnabledFilters(),
false,
null,
this
);

View File

@ -69,6 +69,11 @@ public class FakeSqmToSqlAstConverter extends BaseSemanticQueryWalker implements
return new LoadQueryInfluencers( getCreationContext().getSessionFactory() );
}
@Override
public boolean applyOnlyLoadByKeyFilters() {
return false;
}
@Override
public void registerLockMode(String identificationVariable, LockMode explicitLockMode) {
creationState.registerLockMode( identificationVariable, explicitLockMode );

View File

@ -30,6 +30,8 @@ public interface SqlAstCreationState {
LoadQueryInfluencers getLoadQueryInfluencers();
boolean applyOnlyLoadByKeyFilters();
void registerLockMode(String identificationVariable, LockMode explicitLockMode);
/**

View File

@ -58,7 +58,6 @@ import org.hibernate.metamodel.mapping.JdbcMapping;
import org.hibernate.metamodel.mapping.ModelPart;
import org.hibernate.metamodel.mapping.NaturalIdMapping;
import org.hibernate.metamodel.mapping.TableDetails;
import org.hibernate.metamodel.mapping.ValuedModelPart;
import org.hibernate.metamodel.model.domain.NavigableRole;
import org.hibernate.metamodel.spi.EntityRepresentationStrategy;
import org.hibernate.persister.collection.CollectionPersister;
@ -796,7 +795,7 @@ public class GoofyPersisterClassProvider implements PersisterClassResolver {
}
@Override
public boolean isAffectedByEnabledFilters(LoadQueryInfluencers influencers) {
public boolean isAffectedByEnabledFilters(LoadQueryInfluencers influencers, boolean onlyApplyForLoadByKeyFilters) {
return false;
}
@ -1100,7 +1099,13 @@ public class GoofyPersisterClassProvider implements PersisterClassResolver {
}
@Override
public void applyFilterRestrictions(Consumer<Predicate> predicateConsumer, TableGroup tableGroup, boolean useQualifier, Map<String, Filter> enabledFilters, SqlAstCreationState creationState) {
public void applyFilterRestrictions(
Consumer<Predicate> predicateConsumer,
TableGroup tableGroup,
boolean useQualifier,
Map<String, Filter> enabledFilters,
boolean onlyApplyLoadByKeyFilters,
SqlAstCreationState creationState) {
}
@ -1109,6 +1114,18 @@ public class GoofyPersisterClassProvider implements PersisterClassResolver {
}
@Override
public void applyBaseRestrictions(
Consumer<Predicate> predicateConsumer,
TableGroup tableGroup,
boolean useQualifier,
Map<String, Filter> enabledFilters,
boolean onlyApplyLoadByKeyFilters,
Set<String> treatAsDeclarations,
SqlAstCreationState creationState) {
}
@Override
public boolean hasWhereRestrictions() {
return false;

View File

@ -785,7 +785,7 @@ public class PersisterClassProviderTest {
}
@Override
public boolean isAffectedByEnabledFilters(LoadQueryInfluencers influencers) {
public boolean isAffectedByEnabledFilters(LoadQueryInfluencers influencers, boolean onlyApplyForLoadByKeyFilters) {
return false;
}

View File

@ -942,7 +942,7 @@ public class CustomPersister implements EntityPersister {
}
@Override
public boolean isAffectedByEnabledFilters(LoadQueryInfluencers loadQueryInfluencers) {
public boolean isAffectedByEnabledFilters(LoadQueryInfluencers influencers, boolean onlyApplyForLoadByKeyFilters) {
return false;
}

View File

@ -112,6 +112,7 @@ public class FilterTest extends BaseEntityManagerFunctionalTestCase {
@After
public void tearDown() {
doInJPA(this::entityManagerFactory, entityManager -> {
entityManager.createQuery( "update Account set parentAccount = null" ).executeUpdate();
entityManager.createQuery( "delete from Account" ).executeUpdate();
entityManager.createQuery( "delete from Client" ).executeUpdate();
});
@ -306,6 +307,21 @@ public class FilterTest extends BaseEntityManagerFunctionalTestCase {
// Account with id 1 does not exist
assertTrue( exception.getMessage().contains( "`1`" ) );
});
doInJPA(this::entityManagerFactory, entityManager -> {
entityManager.unwrap(Session.class)
.enableFilter("accountType")
.setParameter("type", "DEBIT");
FetchNotFoundException exception = assertThrows(
FetchNotFoundException.class,
() -> entityManager.createQuery(
"select a from Account a left join fetch a.parentAccount where a.id = 2",
Account.class
).getResultList()
);
// Account with id 1 does not exist
assertTrue( exception.getMessage().contains( "`1`" ) );
});
}
public enum AccountType {