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;
import java.math.BigDecimal;
import java.math.BigInteger;
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 jakarta.persistence.TemporalType;
import jakarta.persistence.metamodel.SingularAttribute;
import jakarta.persistence.metamodel.Type;
import org.hibernate.HibernateException;
import org.hibernate.Internal;
import org.hibernate.LockMode;
import org.hibernate.boot.model.process.internal.InferredBasicValueResolver;
import org.hibernate.dialect.DmlTargetColumnQualifierSupport;
import org.hibernate.dialect.Dialect;
import org.hibernate.dialect.DmlTargetColumnQualifierSupport;
import org.hibernate.dialect.function.TimestampaddFunction;
import org.hibernate.dialect.function.TimestampdiffFunction;
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.JdbcMappingContainer;
import org.hibernate.metamodel.mapping.MappingModelExpressible;
import org.hibernate.metamodel.mapping.MappingType;
import org.hibernate.metamodel.mapping.ModelPart;
import org.hibernate.metamodel.mapping.ModelPartContainer;
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.BasicSqmPathSource;
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.EntityDiscriminatorSqmPath;
import org.hibernate.metamodel.model.domain.internal.EntityTypeImpl;
import org.hibernate.metamodel.spi.MappingMetamodelImplementor;
import org.hibernate.persister.entity.AbstractEntityPersister;
@ -117,6 +98,7 @@ import org.hibernate.query.BindableType;
import org.hibernate.query.QueryLogging;
import org.hibernate.query.ReturnableType;
import org.hibernate.query.SemanticException;
import org.hibernate.query.SortDirection;
import org.hibernate.query.criteria.JpaCteCriteriaAttribute;
import org.hibernate.query.criteria.JpaPath;
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.FetchClauseType;
import org.hibernate.query.sqm.InterpretationException;
import org.hibernate.query.SortDirection;
import org.hibernate.query.sqm.SqmExpressible;
import org.hibernate.query.sqm.SqmPathSource;
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.usertype.UserVersionType;
import org.hibernate.usertype.internal.AbstractTimeZoneStorageCompositeUserType;
import org.jboss.logging.Logger;
import jakarta.persistence.TemporalType;
import jakarta.persistence.metamodel.SingularAttribute;
import jakarta.persistence.metamodel.Type;
import java.math.BigDecimal;
import java.math.BigInteger;
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 org.hibernate.generator.EventType.INSERT;
@ -7962,6 +7961,8 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
boolean explicitFetch = false;
EntityGraphTraversalState.TraversalResult traversalResult = null;
TableGroup joinedTableGroup = null;
if ( fetchedJoin != null ) {
fetchablePath = fetchedJoin.getNavigablePath();
// 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 ) {
fromClauseIndex.resolveTableGroup(
joinedTableGroup = fromClauseIndex.resolveTableGroup(
fetchablePath,
np -> {
// generate the join
@ -8099,22 +8100,40 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
sqlSelectionsToTrack.getValue().addAll( selections.subList( sqlSelectionStartIndexForFetch, selections.size() ) );
}
if ( fetch != null ) {
if ( fetch.getTiming() == FetchTiming.IMMEDIATE && 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()
)
if ( fetch != null && fetch.getTiming() == FetchTiming.IMMEDIATE ) {
if ( fetchable instanceof TableGroupJoinProducer ) {
if ( joinedTableGroup != null ) {
final TableGroup actualTableGroup = joinedTableGroup instanceof PluralTableGroup ?
( (PluralTableGroup) joinedTableGroup ).getElementTableGroup() :
joinedTableGroup;
final MappingType entityMappingType = actualTableGroup == null
? null
: actualTableGroup.getModelPart().getPartMappingType();
if ( entityMappingType instanceof EntityMappingType ) {
registerEntityNameUsage(
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.testing.TestForIssue;
import org.hibernate.testing.orm.junit.JiraKey;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
@ -55,8 +56,8 @@ public class EntityGraphTest extends BaseEntityManagerFunctionalTestCase {
@Override
protected Class<?>[] getAnnotatedClasses() {
return new Class[] {
Foo.class, Bar.class, Baz.class, Author.class, Book.class, Prize.class,
Company.class, Employee.class, Manager.class, Location.class, Animal.class, Dog.class, Cat.class
Foo.class, Bar.class, Baz.class, Author.class, Book.class, Prize.class, Company.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();
}
@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
@Table(name = "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
@Inheritance(strategy = InheritanceType.JOINED)
public static abstract class Animal {