diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/ManagedMappingType.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/ManagedMappingType.java index a2ff2c67a662..c57d9f2ed039 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/ManagedMappingType.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/ManagedMappingType.java @@ -124,6 +124,14 @@ default boolean isAffectedByEnabledFilters( if ( !visitedTypes.add( this ) ) { return false; } + + return areAttributesAffectedByEnabledFilters( visitedTypes, influencers, onlyApplyForLoadByKey ); + } + + default boolean areAttributesAffectedByEnabledFilters( + Set visitedTypes, + LoadQueryInfluencers influencers, + boolean onlyApplyForLoadByKey) { // 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++ ) { diff --git a/hibernate-core/src/main/java/org/hibernate/persister/collection/AbstractCollectionPersister.java b/hibernate-core/src/main/java/org/hibernate/persister/collection/AbstractCollectionPersister.java index 8f9d8968cccc..fe2ad0cee8ad 100644 --- a/hibernate-core/src/main/java/org/hibernate/persister/collection/AbstractCollectionPersister.java +++ b/hibernate-core/src/main/java/org/hibernate/persister/collection/AbstractCollectionPersister.java @@ -1454,7 +1454,8 @@ private boolean exists(Object key, Object indexOrElement, Type indexOrElementTyp @Override public Object getElementByIndex(Object key, Object index, SharedSessionContractImplementor session, Object owner) { final var influencers = session.getLoadQueryInfluencers(); - if ( isAffectedByFilters( new HashSet<>(), attributeMapping.getElementDescriptor(), influencers, true ) ) { + if ( influencers.hasEnabledFilters() + && isAffectedByFilters( new HashSet<>(), attributeMapping.getElementDescriptor(), influencers, true ) ) { return new CollectionElementLoaderByIndex( attributeMapping, influencers, factory ) .load( key, index, session ); } @@ -1537,7 +1538,7 @@ public boolean isAffectedByEnabledFilters(LoadQueryInfluencers influencers, bool final var enabledFilters = influencers.getEnabledFilters(); return filterHelper != null && filterHelper.isAffectedBy( enabledFilters ) || manyToManyFilterHelper != null && manyToManyFilterHelper.isAffectedBy( enabledFilters ) - || isKeyOrElementAffectedByFilters( new HashSet<>(), influencers, onlyApplyForLoadByKeyFilters); + || isKeyOrElementAffectedByFilters( new HashSet<>(), influencers, onlyApplyForLoadByKeyFilters ); } else { return false; @@ -1549,15 +1550,11 @@ public boolean isAffectedByEnabledFilters( Set visitedTypes, LoadQueryInfluencers influencers, boolean onlyApplyForLoadByKeyFilters) { - if ( influencers.hasEnabledFilters() ) { - final var enabledFilters = influencers.getEnabledFilters(); - return filterHelper != null && filterHelper.isAffectedBy( enabledFilters ) - || manyToManyFilterHelper != null && manyToManyFilterHelper.isAffectedBy( enabledFilters ) - || isKeyOrElementAffectedByFilters( visitedTypes, influencers, onlyApplyForLoadByKeyFilters); - } - else { - return false; - } + assert influencers.hasEnabledFilters(); + final var enabledFilters = influencers.getEnabledFilters(); + return filterHelper != null && filterHelper.isAffectedBy( enabledFilters ) + || manyToManyFilterHelper != null && manyToManyFilterHelper.isAffectedBy( enabledFilters ) + || isKeyOrElementAffectedByFilters( visitedTypes, influencers, onlyApplyForLoadByKeyFilters ); } private boolean isKeyOrElementAffectedByFilters( diff --git a/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java b/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java index dee04d4063bd..875e11e0ef80 100644 --- a/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java +++ b/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java @@ -3665,14 +3665,22 @@ public boolean isAffectedByEnabledFetchProfiles(LoadQueryInfluencers loadQueryIn public boolean isAffectedByEnabledFilters( LoadQueryInfluencers loadQueryInfluencers, boolean onlyApplyForLoadByKeyFilters) { - if ( filterHelper != null && loadQueryInfluencers.hasEnabledFilters() ) { - return filterHelper.isAffectedBy( loadQueryInfluencers.getEnabledFilters(), onlyApplyForLoadByKeyFilters ) - || isAffectedByEnabledFilters( new HashSet<>(), loadQueryInfluencers, onlyApplyForLoadByKeyFilters ); + return loadQueryInfluencers.hasEnabledFilters() + && isAffectedByEnabledFilters( new HashSet<>(), loadQueryInfluencers, onlyApplyForLoadByKeyFilters ); + } - } - else { + @Override + public boolean isAffectedByEnabledFilters( + Set visitedTypes, + LoadQueryInfluencers influencers, + boolean onlyApplyForLoadByKey) { + assert influencers.hasEnabledFilters(); + if ( !visitedTypes.add( this ) ) { return false; } + return filterHelper != null + && filterHelper.isAffectedBy( influencers.getEnabledFilters(), onlyApplyForLoadByKey ) + || areAttributesAffectedByEnabledFilters( visitedTypes, influencers, onlyApplyForLoadByKey ); } /** diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/where/annotations/ManyToOneFilterTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/where/annotations/ManyToOneFilterTest.java new file mode 100644 index 000000000000..d8864f5e36cc --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/where/annotations/ManyToOneFilterTest.java @@ -0,0 +1,82 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.orm.test.where.annotations; + +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.Table; +import org.hibernate.EntityFilterException; +import org.hibernate.annotations.Filter; +import org.hibernate.annotations.FilterDef; +import org.hibernate.testing.orm.junit.DomainModel; +import org.hibernate.testing.orm.junit.SessionFactory; +import org.hibernate.testing.orm.junit.SessionFactoryScope; +import org.junit.jupiter.api.Test; + +import static org.junit.Assert.assertNotNull; +import static org.junit.jupiter.api.Assertions.fail; + +@SessionFactory +@DomainModel(annotatedClasses = + {ManyToOneFilterTest.X.class, + ManyToOneFilterTest.Y.class}) +class ManyToOneFilterTest { + @Test void test(SessionFactoryScope scope) { + scope.inTransaction(session -> { + Y y = new Y(); + X x = new X(); + x.id = -1; + y.x = x; + session.persist(x); + session.persist(y); + }); + scope.inTransaction(session -> { + Y y = session.find(Y.class, 0L); + assertNotNull(y.x); + }); + try { + scope.inTransaction( session -> { + session.enableFilter( "filter" ).validate(); + var graph = session.createEntityGraph(Y.class); + Y y = session.find( graph, 0L ); + } ); + fail(); + } + catch (EntityFilterException efe) { + //required + } + try { + scope.inTransaction(session -> { + session.enableFilter( "filter" ).validate(); + Y y = session.find(Y.class, 0L); + }); + fail(); + } + catch (EntityFilterException efe) { + //required + } + } + + @Entity + @Table(name = "XX") + @FilterDef(name = "filter", applyToLoadByKey = true) + @Filter(name = "filter", condition = "id>0") + static class X { + @Id + long id; + } + @Entity + @Table(name = "YY") + static class Y { + @Id + long id; + String name; + @ManyToOne + @JoinColumn(name = "xx") + X x; + } +}