HHH-17192 Register entity name usage for entity graph/fetch profile related join fetches

This commit is contained in:
The-Huginn 2023-09-26 13:38:05 +02:00 committed by Christian Beikov
parent 9db13eed69
commit e17590a18f
2 changed files with 107 additions and 47 deletions

View File

@ -6,35 +6,15 @@
*/ */
package org.hibernate.query.sqm.sql; package org.hibernate.query.sqm.sql;
import java.math.BigDecimal; import jakarta.persistence.TemporalType;
import java.math.BigInteger; import jakarta.persistence.metamodel.SingularAttribute;
import java.sql.PreparedStatement; import jakarta.persistence.metamodel.Type;
import java.sql.SQLException;
import java.util.AbstractMap;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.IdentityHashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;
import org.hibernate.HibernateException; import org.hibernate.HibernateException;
import org.hibernate.Internal; import org.hibernate.Internal;
import org.hibernate.LockMode; import org.hibernate.LockMode;
import org.hibernate.boot.model.process.internal.InferredBasicValueResolver; import org.hibernate.boot.model.process.internal.InferredBasicValueResolver;
import org.hibernate.dialect.DmlTargetColumnQualifierSupport;
import org.hibernate.dialect.Dialect; import org.hibernate.dialect.Dialect;
import org.hibernate.dialect.DmlTargetColumnQualifierSupport;
import org.hibernate.dialect.function.TimestampaddFunction; import org.hibernate.dialect.function.TimestampaddFunction;
import org.hibernate.dialect.function.TimestampdiffFunction; import org.hibernate.dialect.function.TimestampdiffFunction;
import org.hibernate.engine.FetchStyle; import org.hibernate.engine.FetchStyle;
@ -79,6 +59,7 @@ import org.hibernate.metamodel.mapping.ForeignKeyDescriptor;
import org.hibernate.metamodel.mapping.JdbcMapping; import org.hibernate.metamodel.mapping.JdbcMapping;
import org.hibernate.metamodel.mapping.JdbcMappingContainer; import org.hibernate.metamodel.mapping.JdbcMappingContainer;
import org.hibernate.metamodel.mapping.MappingModelExpressible; import org.hibernate.metamodel.mapping.MappingModelExpressible;
import org.hibernate.metamodel.mapping.MappingType;
import org.hibernate.metamodel.mapping.ModelPart; import org.hibernate.metamodel.mapping.ModelPart;
import org.hibernate.metamodel.mapping.ModelPartContainer; import org.hibernate.metamodel.mapping.ModelPartContainer;
import org.hibernate.metamodel.mapping.PluralAttributeMapping; import org.hibernate.metamodel.mapping.PluralAttributeMapping;
@ -105,8 +86,8 @@ import org.hibernate.metamodel.model.domain.internal.AnyDiscriminatorSqmPath;
import org.hibernate.metamodel.model.domain.internal.AnyDiscriminatorSqmPathSource; import org.hibernate.metamodel.model.domain.internal.AnyDiscriminatorSqmPathSource;
import org.hibernate.metamodel.model.domain.internal.BasicSqmPathSource; import org.hibernate.metamodel.model.domain.internal.BasicSqmPathSource;
import org.hibernate.metamodel.model.domain.internal.CompositeSqmPathSource; import org.hibernate.metamodel.model.domain.internal.CompositeSqmPathSource;
import org.hibernate.metamodel.model.domain.internal.EntityDiscriminatorSqmPath;
import org.hibernate.metamodel.model.domain.internal.EmbeddedSqmPathSource; import org.hibernate.metamodel.model.domain.internal.EmbeddedSqmPathSource;
import org.hibernate.metamodel.model.domain.internal.EntityDiscriminatorSqmPath;
import org.hibernate.metamodel.model.domain.internal.EntityTypeImpl; import org.hibernate.metamodel.model.domain.internal.EntityTypeImpl;
import org.hibernate.metamodel.spi.MappingMetamodelImplementor; import org.hibernate.metamodel.spi.MappingMetamodelImplementor;
import org.hibernate.persister.entity.AbstractEntityPersister; import org.hibernate.persister.entity.AbstractEntityPersister;
@ -117,6 +98,7 @@ import org.hibernate.query.BindableType;
import org.hibernate.query.QueryLogging; import org.hibernate.query.QueryLogging;
import org.hibernate.query.ReturnableType; import org.hibernate.query.ReturnableType;
import org.hibernate.query.SemanticException; import org.hibernate.query.SemanticException;
import org.hibernate.query.SortDirection;
import org.hibernate.query.criteria.JpaCteCriteriaAttribute; import org.hibernate.query.criteria.JpaCteCriteriaAttribute;
import org.hibernate.query.criteria.JpaPath; import org.hibernate.query.criteria.JpaPath;
import org.hibernate.query.criteria.JpaSearchOrder; import org.hibernate.query.criteria.JpaSearchOrder;
@ -134,7 +116,6 @@ import org.hibernate.query.sqm.ComparisonOperator;
import org.hibernate.query.sqm.DynamicInstantiationNature; import org.hibernate.query.sqm.DynamicInstantiationNature;
import org.hibernate.query.sqm.FetchClauseType; import org.hibernate.query.sqm.FetchClauseType;
import org.hibernate.query.sqm.InterpretationException; import org.hibernate.query.sqm.InterpretationException;
import org.hibernate.query.SortDirection;
import org.hibernate.query.sqm.SqmExpressible; import org.hibernate.query.sqm.SqmExpressible;
import org.hibernate.query.sqm.SqmPathSource; import org.hibernate.query.sqm.SqmPathSource;
import org.hibernate.query.sqm.SqmQuerySource; import org.hibernate.query.sqm.SqmQuerySource;
@ -412,12 +393,30 @@ import org.hibernate.type.internal.BasicTypeImpl;
import org.hibernate.type.spi.TypeConfiguration; import org.hibernate.type.spi.TypeConfiguration;
import org.hibernate.usertype.UserVersionType; import org.hibernate.usertype.UserVersionType;
import org.hibernate.usertype.internal.AbstractTimeZoneStorageCompositeUserType; import org.hibernate.usertype.internal.AbstractTimeZoneStorageCompositeUserType;
import org.jboss.logging.Logger; import org.jboss.logging.Logger;
import jakarta.persistence.TemporalType; import java.math.BigDecimal;
import jakarta.persistence.metamodel.SingularAttribute; import java.math.BigInteger;
import jakarta.persistence.metamodel.Type; import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.AbstractMap;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.IdentityHashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;
import static java.util.Collections.singletonList; import static java.util.Collections.singletonList;
import static org.hibernate.generator.EventType.INSERT; import static org.hibernate.generator.EventType.INSERT;
@ -7962,6 +7961,8 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
boolean explicitFetch = false; boolean explicitFetch = false;
EntityGraphTraversalState.TraversalResult traversalResult = null; EntityGraphTraversalState.TraversalResult traversalResult = null;
TableGroup joinedTableGroup = null;
if ( fetchedJoin != null ) { if ( fetchedJoin != null ) {
fetchablePath = fetchedJoin.getNavigablePath(); fetchablePath = fetchedJoin.getNavigablePath();
// there was an explicit fetch in the SQM // there was an explicit fetch in the SQM
@ -8043,7 +8044,7 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
} }
if ( joined && fetchable instanceof TableGroupJoinProducer ) { if ( joined && fetchable instanceof TableGroupJoinProducer ) {
fromClauseIndex.resolveTableGroup( joinedTableGroup = fromClauseIndex.resolveTableGroup(
fetchablePath, fetchablePath,
np -> { np -> {
// generate the join // generate the join
@ -8099,22 +8100,40 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
sqlSelectionsToTrack.getValue().addAll( selections.subList( sqlSelectionStartIndexForFetch, selections.size() ) ); sqlSelectionsToTrack.getValue().addAll( selections.subList( sqlSelectionStartIndexForFetch, selections.size() ) );
} }
if ( fetch != null ) { if ( fetch != null && fetch.getTiming() == FetchTiming.IMMEDIATE ) {
if ( fetch.getTiming() == FetchTiming.IMMEDIATE && fetchable instanceof PluralAttributeMapping ) { if ( fetchable instanceof TableGroupJoinProducer ) {
final PluralAttributeMapping pluralAttributeMapping = (PluralAttributeMapping) fetchable; if ( joinedTableGroup != null ) {
final CollectionClassification collectionClassification = pluralAttributeMapping.getMappedType() final TableGroup actualTableGroup = joinedTableGroup instanceof PluralTableGroup ?
.getCollectionSemantics() ( (PluralTableGroup) joinedTableGroup ).getElementTableGroup() :
.getCollectionClassification(); joinedTableGroup;
if ( collectionClassification == CollectionClassification.BAG ) { final MappingType entityMappingType = actualTableGroup == null
if ( currentBagRole != null ) { ? null
throw new MultipleBagFetchException( : actualTableGroup.getModelPart().getPartMappingType();
Arrays.asList( if ( entityMappingType instanceof EntityMappingType ) {
currentBagRole, registerEntityNameUsage(
fetchable.getNavigableRole().getNavigableName() actualTableGroup,
) EntityNameUse.PROJECTION,
( (EntityMappingType) entityMappingType ).getEntityName(),
true
); );
} }
currentBagRole = fetchable.getNavigableRole().getNavigableName(); }
if ( fetchable instanceof PluralAttributeMapping ) {
final PluralAttributeMapping pluralAttributeMapping = (PluralAttributeMapping) fetchable;
final CollectionClassification collectionClassification = pluralAttributeMapping.getMappedType()
.getCollectionSemantics()
.getCollectionClassification();
if ( collectionClassification == CollectionClassification.BAG ) {
if ( currentBagRole != null ) {
throw new MultipleBagFetchException(
Arrays.asList(
currentBagRole,
fetchable.getNavigableRole().getNavigableName()
)
);
}
currentBagRole = fetchable.getNavigableRole().getNavigableName();
}
} }
} }
} }

View File

@ -40,6 +40,7 @@ import org.hibernate.testing.util.uuid.SafeRandomUUIDGenerator;
import org.hibernate.orm.test.jpa.BaseEntityManagerFunctionalTestCase; import org.hibernate.orm.test.jpa.BaseEntityManagerFunctionalTestCase;
import org.hibernate.testing.TestForIssue; import org.hibernate.testing.TestForIssue;
import org.hibernate.testing.orm.junit.JiraKey;
import org.junit.Test; import org.junit.Test;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
@ -55,8 +56,8 @@ public class EntityGraphTest extends BaseEntityManagerFunctionalTestCase {
@Override @Override
protected Class<?>[] getAnnotatedClasses() { protected Class<?>[] getAnnotatedClasses() {
return new Class[] { return new Class[] {
Foo.class, Bar.class, Baz.class, Author.class, Book.class, Prize.class, Foo.class, Bar.class, Baz.class, Author.class, Book.class, Prize.class, Company.class,
Company.class, Employee.class, Manager.class, Location.class, Animal.class, Dog.class, Cat.class Employee.class, Manager.class, Location.class, AnimalOwner.class, Animal.class, Dog.class, Cat.class
}; };
} }
@ -454,6 +455,36 @@ public class EntityGraphTest extends BaseEntityManagerFunctionalTestCase {
em.close(); em.close();
} }
@Test
@JiraKey("HHH-17192")
public void joinedInheritanceWithSubEntityAttributeFiltering() {
EntityManager em = getOrCreateEntityManager();
em.getTransaction().begin();
Dog dog = new Dog();
em.persist( dog );
AnimalOwner animalOwner = new AnimalOwner();
animalOwner.animal = dog;
em.persist( animalOwner );
em.flush();
em.clear();
EntityGraph<AnimalOwner> entityGraph = em.createEntityGraph( AnimalOwner.class );
entityGraph.addAttributeNodes( "animal" );
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<AnimalOwner> query = cb.createQuery( AnimalOwner.class );
Root<AnimalOwner> root = query.from( AnimalOwner.class );
query.where( cb.equal( root.get( "animal" ).get( "id" ), dog.id ) );
AnimalOwner owner = em.createQuery( query )
.setHint( "jakarta.persistence.loadgraph", entityGraph )
.getResultList()
.get( 0 );
assertTrue( Hibernate.isInitialized( owner.animal ) );
assertTrue( owner.animal instanceof Dog );
em.getTransaction().commit();
em.close();
}
@Entity @Entity
@Table(name = "foo") @Table(name = "foo")
public static class Foo { public static class Foo {
@ -557,6 +588,16 @@ public class EntityGraphTest extends BaseEntityManagerFunctionalTestCase {
} }
} }
@Entity
public static class AnimalOwner {
@Id
@GeneratedValue
public Integer id;
@ManyToOne(fetch = FetchType.LAZY)
public Animal animal;
}
@Entity @Entity
@Inheritance(strategy = InheritanceType.JOINED) @Inheritance(strategy = InheritanceType.JOINED)
public static abstract class Animal { public static abstract class Animal {