diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/AbstractPluralAttribute.java b/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/AbstractPluralAttribute.java index f9dd03fde3..116230ccf1 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/AbstractPluralAttribute.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/AbstractPluralAttribute.java @@ -170,7 +170,7 @@ public abstract class AbstractPluralAttribute "`lhs` cannot be null for a sub-navigable reference - " + getName() ); } - final SqmPathSource parentPathSource = parent.getReferencedPathSource(); + final SqmPathSource parentPathSource = parent.getResolvedModel(); NavigablePath navigablePath = parent.getNavigablePath(); if ( parentPathSource instanceof PluralPersistentAttribute ) { navigablePath = navigablePath.append( CollectionPart.Nature.ELEMENT.getName() ); diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/EmbeddedSqmPathSource.java b/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/EmbeddedSqmPathSource.java index 52b81bb66e..b0f79f2494 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/EmbeddedSqmPathSource.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/EmbeddedSqmPathSource.java @@ -7,6 +7,7 @@ package org.hibernate.metamodel.model.domain.internal; import org.hibernate.metamodel.model.domain.EmbeddableDomainType; +import org.hibernate.query.sqm.SqmJoinable; import org.hibernate.query.sqm.SqmPathSource; import org.hibernate.query.sqm.tree.domain.SqmEmbeddedValuedSimplePath; import org.hibernate.query.sqm.tree.domain.SqmPath; @@ -47,7 +48,9 @@ public class EmbeddedSqmPathSource @Override public SqmPath createSqmPath(SqmPath lhs, SqmPathSource intermediatePathSource) { return new SqmEmbeddedValuedSimplePath<>( - PathHelper.append( lhs, this, intermediatePathSource ), + pathModel instanceof SqmJoinable + ? ( (SqmJoinable) pathModel ).createNavigablePath( lhs, null ) + : PathHelper.append( lhs, this, intermediatePathSource ), pathModel, lhs, lhs.nodeBuilder() diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/SingularAttributeImpl.java b/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/SingularAttributeImpl.java index 38b10b9684..be7d75e4f2 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/SingularAttributeImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/SingularAttributeImpl.java @@ -173,7 +173,7 @@ public class SingularAttributeImpl "LHS cannot be null for a sub-navigable reference - " + getName() ); } - final SqmPathSource parentPathSource = parent.getReferencedPathSource(); + final SqmPathSource parentPathSource = parent.getResolvedModel(); NavigablePath navigablePath = parent.getNavigablePath(); if ( parentPathSource instanceof PluralPersistentAttribute ) { navigablePath = navigablePath.append( CollectionPart.Nature.ELEMENT.getName() ); @@ -224,7 +224,7 @@ public class SingularAttributeImpl ); } NavigablePath navigablePath = parent.getNavigablePath(); - if ( parent.getReferencedPathSource() instanceof PluralPersistentAttribute ) { + if ( parent.getResolvedModel() instanceof PluralPersistentAttribute ) { navigablePath = navigablePath.append( CollectionPart.Nature.ELEMENT.getName() ); } if ( getDeclaringType() instanceof IdentifiableDomainType ) { diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/spi/SqmCreationHelper.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/spi/SqmCreationHelper.java index a5d8797c16..09f187f73d 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/spi/SqmCreationHelper.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/spi/SqmCreationHelper.java @@ -53,7 +53,7 @@ public class SqmCreationHelper { ); } NavigablePath navigablePath = lhs.getNavigablePath(); - if ( lhs.getReferencedPathSource() instanceof PluralPersistentAttribute + if ( lhs.getResolvedModel() instanceof PluralPersistentAttribute && CollectionPart.Nature.fromName( subNavigable ) == null ) { navigablePath = navigablePath.append( CollectionPart.Nature.ELEMENT.getName() ); } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/sql/BaseSqmToSqlAstConverter.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/sql/BaseSqmToSqlAstConverter.java index e0171ec1c6..7af7827cd7 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/sql/BaseSqmToSqlAstConverter.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/sql/BaseSqmToSqlAstConverter.java @@ -5049,7 +5049,11 @@ public abstract class BaseSqmToSqlAstConverter extends Base return expression; } final BasicValuedPathInterpretation basicPath = (BasicValuedPathInterpretation) expression; - final AbstractEntityPersister persister = (AbstractEntityPersister) basicPath.getTableGroup().getModelPart().getPartMappingType(); + final TableGroup tableGroup = basicPath.getTableGroup(); + final TableGroup elementTableGroup = tableGroup instanceof PluralTableGroup + ? ( (PluralTableGroup) tableGroup ).getElementTableGroup() + : tableGroup; + final AbstractEntityPersister persister = (AbstractEntityPersister) elementTableGroup.getModelPart().getPartMappingType(); // Only need a case expression around the basic valued path for the parent treat expression // if the column of the basic valued path is shared between subclasses if ( persister.isSharedColumn( basicPath.getColumnReference().getColumnExpression() ) ) { diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmTreatedBagJoin.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmTreatedBagJoin.java index 3ff7c1e176..6e6b689478 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmTreatedBagJoin.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmTreatedBagJoin.java @@ -103,6 +103,11 @@ public class SqmTreatedBagJoin extends SqmBagJoin impleme return treatTarget; } + @Override + public SqmPathSource getResolvedModel() { + return treatTarget; + } + @Override public SqmAttributeJoin makeCopy(SqmCreationProcessingState creationProcessingState) { return new SqmTreatedBagJoin<>( wrappedPath, treatTarget, getAlias() ); diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmTreatedCrossJoin.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmTreatedCrossJoin.java index f7dfb9a9aa..79c34f0f88 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmTreatedCrossJoin.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmTreatedCrossJoin.java @@ -91,8 +91,12 @@ public class SqmTreatedCrossJoin extends SqmCrossJoin impleme @Override public EntityDomainType getReferencedPathSource() { - //noinspection unchecked - return (EntityDomainType) wrappedPath.getReferencedPathSource(); + return treatTarget; + } + + @Override + public SqmPathSource getResolvedModel() { + return treatTarget; } @Override diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmTreatedEntityJoin.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmTreatedEntityJoin.java index 0b8d145dae..1aa4f99879 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmTreatedEntityJoin.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmTreatedEntityJoin.java @@ -77,6 +77,11 @@ public class SqmTreatedEntityJoin extends SqmEntityJoin imple return treatTarget; } + @Override + public EntityDomainType getModel() { + return getTreatTarget(); + } + @Override public SqmPath getWrappedPath() { return wrappedPath; diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmTreatedListJoin.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmTreatedListJoin.java index e3f5c8f7ce..56706414de 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmTreatedListJoin.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmTreatedListJoin.java @@ -102,6 +102,11 @@ public class SqmTreatedListJoin extends SqmListJoin imple return treatTarget; } + @Override + public SqmPathSource getResolvedModel() { + return treatTarget; + } + @Override public SqmPath resolveIndexedAccess( SqmExpression selector, diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmTreatedMapJoin.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmTreatedMapJoin.java index df076cc0b3..dbf435a627 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmTreatedMapJoin.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmTreatedMapJoin.java @@ -98,6 +98,11 @@ public class SqmTreatedMapJoin extends SqmMapJoin return treatTarget; } + @Override + public SqmPathSource getResolvedModel() { + return treatTarget; + } + @Override public SqmMapJoin makeCopy(SqmCreationProcessingState creationProcessingState) { return new SqmTreatedMapJoin<>( diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmTreatedPluralPartJoin.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmTreatedPluralPartJoin.java index 281aa36756..b7592212e3 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmTreatedPluralPartJoin.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmTreatedPluralPartJoin.java @@ -91,6 +91,16 @@ public class SqmTreatedPluralPartJoin extends SqmPluralPartJoi return treatTarget; } + @Override + public SqmPathSource getReferencedPathSource() { + return treatTarget; + } + + @Override + public SqmPathSource getResolvedModel() { + return treatTarget; + } + @Override public void appendHqlString(StringBuilder sb) { sb.append( "treat(" ); diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmTreatedSetJoin.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmTreatedSetJoin.java index 813d50d100..218363119c 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmTreatedSetJoin.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmTreatedSetJoin.java @@ -100,6 +100,11 @@ public class SqmTreatedSetJoin extends SqmSetJoin impleme return treatTarget; } + @Override + public SqmPathSource getResolvedModel() { + return treatTarget; + } + @Override public SqmAttributeJoin makeCopy(SqmCreationProcessingState creationProcessingState) { return new SqmTreatedSetJoin<>( wrappedPath, treatTarget, getAlias() ); diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmTreatedSimplePath.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmTreatedSimplePath.java index bdbf719277..f2a3d8b273 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmTreatedSimplePath.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmTreatedSimplePath.java @@ -109,6 +109,16 @@ public class SqmTreatedSimplePath return treatTarget; } + @Override + public SqmPathSource getReferencedPathSource() { + return treatTarget; + } + + @Override + public SqmPathSource getResolvedModel() { + return treatTarget; + } + @Override public SqmTreatedSimplePath treatAs(Class treatJavaType) throws PathException { return super.treatAs( treatJavaType ); diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmTreatedSingularJoin.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmTreatedSingularJoin.java index c820b78c23..cc99f78654 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmTreatedSingularJoin.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmTreatedSingularJoin.java @@ -97,7 +97,12 @@ public class SqmTreatedSingularJoin extends SqmSingularJoin getReferencedPathSource() { - return getTreatTarget(); + return treatTarget; + } + + @Override + public SqmPathSource getResolvedModel() { + return treatTarget; } @Override diff --git a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/embeddable/AbstractEmbeddableInitializer.java b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/embeddable/AbstractEmbeddableInitializer.java index 9dc6c04447..b1ee699fcc 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/embeddable/AbstractEmbeddableInitializer.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/embeddable/AbstractEmbeddableInitializer.java @@ -8,13 +8,14 @@ package org.hibernate.sql.results.graph.embeddable; import org.hibernate.engine.internal.ManagedTypeHelper; import org.hibernate.engine.spi.SessionFactoryImplementor; +import org.hibernate.metamodel.internal.AbstractCompositeIdentifierMapping; import org.hibernate.metamodel.mapping.CompositeIdentifierMapping; import org.hibernate.metamodel.mapping.EmbeddableMappingType; import org.hibernate.metamodel.mapping.EmbeddableValuedModelPart; -import org.hibernate.metamodel.mapping.EntityIdentifierMapping; import org.hibernate.metamodel.mapping.ForeignKeyDescriptor; import org.hibernate.metamodel.mapping.VirtualModelPart; -import org.hibernate.metamodel.model.domain.NavigableRole; +import org.hibernate.metamodel.mapping.internal.EmbeddedAttributeMapping; +import org.hibernate.metamodel.mapping.internal.EmbeddedIdentifierMappingImpl; import org.hibernate.metamodel.spi.ValueAccess; import org.hibernate.property.access.spi.PropertyAccess; import org.hibernate.proxy.HibernateProxy; @@ -68,31 +69,20 @@ public abstract class AbstractEmbeddableInitializer extends AbstractFetchParentA final int size = embeddableTypeDescriptor.getNumberOfFetchables(); this.rowState = new Object[ size ]; - this.isPartOfKey = isPartOfKey( embedded, navigablePath ); + this.isPartOfKey = isPartOfKey( embedded, navigablePath, fetchParentAccess ); // We never want to create empty composites for the FK target or PK, otherwise collections would break this.createEmptyCompositesEnabled = !isPartOfKey && embeddableTypeDescriptor.isCreateEmptyCompositesEnabled(); - this.sessionFactory = creationState.getSqlAstCreationContext().getSessionFactory(); this.assemblers = createAssemblers( resultDescriptor, creationState, embeddableTypeDescriptor ); } - private static boolean isPartOfKey(EmbeddableValuedModelPart modelPart, NavigablePath navigablePath) { + private static boolean isPartOfKey(EmbeddableValuedModelPart modelPart, NavigablePath navigablePath, FetchParentAccess fetchParentAccess) { return modelPart.isEntityIdentifierMapping() - || isPartOfKey( navigablePath ) - || modelPart.getNavigableRole() != null && isPartOfKey( modelPart.getNavigableRole() ); - } - - private static boolean isPartOfKey(NavigablePath navigablePath) { - return ForeignKeyDescriptor.PART_NAME.equals( navigablePath.getLocalName() ) + || ForeignKeyDescriptor.PART_NAME.equals( navigablePath.getLocalName() ) || ForeignKeyDescriptor.TARGET_PART_NAME.equals( navigablePath.getLocalName() ) || navigablePath instanceof EntityIdentifierNavigablePath - || navigablePath.getParent().getParent() != null && isPartOfKey( navigablePath.getParent() ); - } - - private static boolean isPartOfKey(NavigableRole navigableRole) { - final NavigableRole parent = navigableRole.getParent(); - return parent != null - && ( parent.getLocalName().equals( EntityIdentifierMapping.ID_ROLE_NAME ) || isPartOfKey( parent ) ); + || fetchParentAccess != null && fetchParentAccess.isEmbeddableInitializer() + && ( (AbstractEmbeddableInitializer) fetchParentAccess ).isPartOfKey; } protected DomainResultAssembler[] createAssemblers( diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/embeddable/EmbeddableAscDescQueryTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/embeddable/EmbeddableAscDescQueryTest.java index 9847df52a4..97532a4ef2 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/embeddable/EmbeddableAscDescQueryTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/embeddable/EmbeddableAscDescQueryTest.java @@ -74,6 +74,7 @@ public class EmbeddableAscDescQueryTest { public void tearDown(SessionFactoryScope scope) { scope.inTransaction( session -> { + session.createMutationQuery( "update EntityA a set a.componentA.entityA = null" ).executeUpdate(); session.createMutationQuery( "delete from EntityB" ).executeUpdate(); session.createMutationQuery( "delete from EntityC" ).executeUpdate(); session.createMutationQuery( "delete from EntityA" ).executeUpdate();