mirror of
https://github.com/hibernate/hibernate-orm
synced 2025-02-17 00:24:57 +00:00
HHH-16997 Embedded components in HibernateProxy are not initialized when entity has reference to another entity of the same type + HHH-16901 Embedded field in entity association from composite key not correctly instantiated
This commit is contained in:
parent
7cb00f3521
commit
22535bbd92
@ -170,7 +170,7 @@ public NavigablePath createNavigablePath(SqmPath<?> parent, String alias) {
|
|||||||
"`lhs` cannot be null for a sub-navigable reference - " + getName()
|
"`lhs` cannot be null for a sub-navigable reference - " + getName()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
final SqmPathSource<?> parentPathSource = parent.getReferencedPathSource();
|
final SqmPathSource<?> parentPathSource = parent.getResolvedModel();
|
||||||
NavigablePath navigablePath = parent.getNavigablePath();
|
NavigablePath navigablePath = parent.getNavigablePath();
|
||||||
if ( parentPathSource instanceof PluralPersistentAttribute<?, ?, ?> ) {
|
if ( parentPathSource instanceof PluralPersistentAttribute<?, ?, ?> ) {
|
||||||
navigablePath = navigablePath.append( CollectionPart.Nature.ELEMENT.getName() );
|
navigablePath = navigablePath.append( CollectionPart.Nature.ELEMENT.getName() );
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
package org.hibernate.metamodel.model.domain.internal;
|
package org.hibernate.metamodel.model.domain.internal;
|
||||||
|
|
||||||
import org.hibernate.metamodel.model.domain.EmbeddableDomainType;
|
import org.hibernate.metamodel.model.domain.EmbeddableDomainType;
|
||||||
|
import org.hibernate.query.sqm.SqmJoinable;
|
||||||
import org.hibernate.query.sqm.SqmPathSource;
|
import org.hibernate.query.sqm.SqmPathSource;
|
||||||
import org.hibernate.query.sqm.tree.domain.SqmEmbeddedValuedSimplePath;
|
import org.hibernate.query.sqm.tree.domain.SqmEmbeddedValuedSimplePath;
|
||||||
import org.hibernate.query.sqm.tree.domain.SqmPath;
|
import org.hibernate.query.sqm.tree.domain.SqmPath;
|
||||||
@ -47,7 +48,9 @@ public boolean isGeneric() {
|
|||||||
@Override
|
@Override
|
||||||
public SqmPath<J> createSqmPath(SqmPath<?> lhs, SqmPathSource<?> intermediatePathSource) {
|
public SqmPath<J> createSqmPath(SqmPath<?> lhs, SqmPathSource<?> intermediatePathSource) {
|
||||||
return new SqmEmbeddedValuedSimplePath<>(
|
return new SqmEmbeddedValuedSimplePath<>(
|
||||||
PathHelper.append( lhs, this, intermediatePathSource ),
|
pathModel instanceof SqmJoinable<?, ?>
|
||||||
|
? ( (SqmJoinable<?, ?>) pathModel ).createNavigablePath( lhs, null )
|
||||||
|
: PathHelper.append( lhs, this, intermediatePathSource ),
|
||||||
pathModel,
|
pathModel,
|
||||||
lhs,
|
lhs,
|
||||||
lhs.nodeBuilder()
|
lhs.nodeBuilder()
|
||||||
|
@ -173,7 +173,7 @@ public NavigablePath createNavigablePath(SqmPath<?> parent, String alias) {
|
|||||||
"LHS cannot be null for a sub-navigable reference - " + getName()
|
"LHS cannot be null for a sub-navigable reference - " + getName()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
final SqmPathSource<?> parentPathSource = parent.getReferencedPathSource();
|
final SqmPathSource<?> parentPathSource = parent.getResolvedModel();
|
||||||
NavigablePath navigablePath = parent.getNavigablePath();
|
NavigablePath navigablePath = parent.getNavigablePath();
|
||||||
if ( parentPathSource instanceof PluralPersistentAttribute<?, ?, ?> ) {
|
if ( parentPathSource instanceof PluralPersistentAttribute<?, ?, ?> ) {
|
||||||
navigablePath = navigablePath.append( CollectionPart.Nature.ELEMENT.getName() );
|
navigablePath = navigablePath.append( CollectionPart.Nature.ELEMENT.getName() );
|
||||||
@ -224,7 +224,7 @@ public NavigablePath createNavigablePath(SqmPath<?> parent, String alias) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
NavigablePath navigablePath = parent.getNavigablePath();
|
NavigablePath navigablePath = parent.getNavigablePath();
|
||||||
if ( parent.getReferencedPathSource() instanceof PluralPersistentAttribute<?, ?, ?> ) {
|
if ( parent.getResolvedModel() instanceof PluralPersistentAttribute<?, ?, ?> ) {
|
||||||
navigablePath = navigablePath.append( CollectionPart.Nature.ELEMENT.getName() );
|
navigablePath = navigablePath.append( CollectionPart.Nature.ELEMENT.getName() );
|
||||||
}
|
}
|
||||||
if ( getDeclaringType() instanceof IdentifiableDomainType<?> ) {
|
if ( getDeclaringType() instanceof IdentifiableDomainType<?> ) {
|
||||||
|
@ -53,7 +53,7 @@ public static NavigablePath buildSubNavigablePath(SqmPath<?> lhs, String subNavi
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
NavigablePath navigablePath = lhs.getNavigablePath();
|
NavigablePath navigablePath = lhs.getNavigablePath();
|
||||||
if ( lhs.getReferencedPathSource() instanceof PluralPersistentAttribute<?, ?, ?>
|
if ( lhs.getResolvedModel() instanceof PluralPersistentAttribute<?, ?, ?>
|
||||||
&& CollectionPart.Nature.fromName( subNavigable ) == null ) {
|
&& CollectionPart.Nature.fromName( subNavigable ) == null ) {
|
||||||
navigablePath = navigablePath.append( CollectionPart.Nature.ELEMENT.getName() );
|
navigablePath = navigablePath.append( CollectionPart.Nature.ELEMENT.getName() );
|
||||||
}
|
}
|
||||||
|
@ -5049,7 +5049,11 @@ private Expression withTreatRestriction(Expression expression, SqmPath<?> path)
|
|||||||
return expression;
|
return expression;
|
||||||
}
|
}
|
||||||
final BasicValuedPathInterpretation<?> basicPath = (BasicValuedPathInterpretation<?>) 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
|
// 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 the column of the basic valued path is shared between subclasses
|
||||||
if ( persister.isSharedColumn( basicPath.getColumnReference().getColumnExpression() ) ) {
|
if ( persister.isSharedColumn( basicPath.getColumnReference().getColumnExpression() ) ) {
|
||||||
|
@ -103,6 +103,11 @@ public EntityDomainType<S> getReferencedPathSource() {
|
|||||||
return treatTarget;
|
return treatTarget;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SqmPathSource<?> getResolvedModel() {
|
||||||
|
return treatTarget;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SqmAttributeJoin<O, S> makeCopy(SqmCreationProcessingState creationProcessingState) {
|
public SqmAttributeJoin<O, S> makeCopy(SqmCreationProcessingState creationProcessingState) {
|
||||||
return new SqmTreatedBagJoin<>( wrappedPath, treatTarget, getAlias() );
|
return new SqmTreatedBagJoin<>( wrappedPath, treatTarget, getAlias() );
|
||||||
|
@ -91,8 +91,12 @@ public SqmPathSource<S> getNodeType() {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public EntityDomainType<S> getReferencedPathSource() {
|
public EntityDomainType<S> getReferencedPathSource() {
|
||||||
//noinspection unchecked
|
return treatTarget;
|
||||||
return (EntityDomainType<S>) wrappedPath.getReferencedPathSource();
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SqmPathSource<?> getResolvedModel() {
|
||||||
|
return treatTarget;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -77,6 +77,11 @@ public EntityDomainType<S> getTreatTarget() {
|
|||||||
return treatTarget;
|
return treatTarget;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public EntityDomainType<S> getModel() {
|
||||||
|
return getTreatTarget();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SqmPath<T> getWrappedPath() {
|
public SqmPath<T> getWrappedPath() {
|
||||||
return wrappedPath;
|
return wrappedPath;
|
||||||
|
@ -102,6 +102,11 @@ public EntityDomainType<S> getReferencedPathSource() {
|
|||||||
return treatTarget;
|
return treatTarget;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SqmPathSource<?> getResolvedModel() {
|
||||||
|
return treatTarget;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SqmPath<?> resolveIndexedAccess(
|
public SqmPath<?> resolveIndexedAccess(
|
||||||
SqmExpression<?> selector,
|
SqmExpression<?> selector,
|
||||||
|
@ -98,6 +98,11 @@ public EntityDomainType<S> getReferencedPathSource() {
|
|||||||
return treatTarget;
|
return treatTarget;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SqmPathSource<?> getResolvedModel() {
|
||||||
|
return treatTarget;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SqmMapJoin<O, K, S> makeCopy(SqmCreationProcessingState creationProcessingState) {
|
public SqmMapJoin<O, K, S> makeCopy(SqmCreationProcessingState creationProcessingState) {
|
||||||
return new SqmTreatedMapJoin<>(
|
return new SqmTreatedMapJoin<>(
|
||||||
|
@ -91,6 +91,16 @@ public SqmPathSource<S> getNodeType() {
|
|||||||
return treatTarget;
|
return treatTarget;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SqmPathSource<S> getReferencedPathSource() {
|
||||||
|
return treatTarget;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SqmPathSource<?> getResolvedModel() {
|
||||||
|
return treatTarget;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void appendHqlString(StringBuilder sb) {
|
public void appendHqlString(StringBuilder sb) {
|
||||||
sb.append( "treat(" );
|
sb.append( "treat(" );
|
||||||
|
@ -100,6 +100,11 @@ public EntityDomainType<S> getReferencedPathSource() {
|
|||||||
return treatTarget;
|
return treatTarget;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SqmPathSource<?> getResolvedModel() {
|
||||||
|
return treatTarget;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SqmAttributeJoin<O, S> makeCopy(SqmCreationProcessingState creationProcessingState) {
|
public SqmAttributeJoin<O, S> makeCopy(SqmCreationProcessingState creationProcessingState) {
|
||||||
return new SqmTreatedSetJoin<>( wrappedPath, treatTarget, getAlias() );
|
return new SqmTreatedSetJoin<>( wrappedPath, treatTarget, getAlias() );
|
||||||
|
@ -109,6 +109,16 @@ public EntityDomainType<S> getNodeType() {
|
|||||||
return treatTarget;
|
return treatTarget;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SqmPathSource<S> getReferencedPathSource() {
|
||||||
|
return treatTarget;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SqmPathSource<?> getResolvedModel() {
|
||||||
|
return treatTarget;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <S1 extends S> SqmTreatedSimplePath<S,S1> treatAs(Class<S1> treatJavaType) throws PathException {
|
public <S1 extends S> SqmTreatedSimplePath<S,S1> treatAs(Class<S1> treatJavaType) throws PathException {
|
||||||
return super.treatAs( treatJavaType );
|
return super.treatAs( treatJavaType );
|
||||||
|
@ -97,7 +97,12 @@ public SqmPathSource<S> getNodeType() {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public EntityDomainType<S> getReferencedPathSource() {
|
public EntityDomainType<S> getReferencedPathSource() {
|
||||||
return getTreatTarget();
|
return treatTarget;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SqmPathSource<?> getResolvedModel() {
|
||||||
|
return treatTarget;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -8,13 +8,14 @@
|
|||||||
|
|
||||||
import org.hibernate.engine.internal.ManagedTypeHelper;
|
import org.hibernate.engine.internal.ManagedTypeHelper;
|
||||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||||
|
import org.hibernate.metamodel.internal.AbstractCompositeIdentifierMapping;
|
||||||
import org.hibernate.metamodel.mapping.CompositeIdentifierMapping;
|
import org.hibernate.metamodel.mapping.CompositeIdentifierMapping;
|
||||||
import org.hibernate.metamodel.mapping.EmbeddableMappingType;
|
import org.hibernate.metamodel.mapping.EmbeddableMappingType;
|
||||||
import org.hibernate.metamodel.mapping.EmbeddableValuedModelPart;
|
import org.hibernate.metamodel.mapping.EmbeddableValuedModelPart;
|
||||||
import org.hibernate.metamodel.mapping.EntityIdentifierMapping;
|
|
||||||
import org.hibernate.metamodel.mapping.ForeignKeyDescriptor;
|
import org.hibernate.metamodel.mapping.ForeignKeyDescriptor;
|
||||||
import org.hibernate.metamodel.mapping.VirtualModelPart;
|
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.metamodel.spi.ValueAccess;
|
||||||
import org.hibernate.property.access.spi.PropertyAccess;
|
import org.hibernate.property.access.spi.PropertyAccess;
|
||||||
import org.hibernate.proxy.HibernateProxy;
|
import org.hibernate.proxy.HibernateProxy;
|
||||||
@ -68,31 +69,20 @@ public AbstractEmbeddableInitializer(
|
|||||||
final int size = embeddableTypeDescriptor.getNumberOfFetchables();
|
final int size = embeddableTypeDescriptor.getNumberOfFetchables();
|
||||||
this.rowState = new Object[ size ];
|
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
|
// We never want to create empty composites for the FK target or PK, otherwise collections would break
|
||||||
this.createEmptyCompositesEnabled = !isPartOfKey && embeddableTypeDescriptor.isCreateEmptyCompositesEnabled();
|
this.createEmptyCompositesEnabled = !isPartOfKey && embeddableTypeDescriptor.isCreateEmptyCompositesEnabled();
|
||||||
|
|
||||||
this.sessionFactory = creationState.getSqlAstCreationContext().getSessionFactory();
|
this.sessionFactory = creationState.getSqlAstCreationContext().getSessionFactory();
|
||||||
this.assemblers = createAssemblers( resultDescriptor, creationState, embeddableTypeDescriptor );
|
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()
|
return modelPart.isEntityIdentifierMapping()
|
||||||
|| isPartOfKey( navigablePath )
|
|| ForeignKeyDescriptor.PART_NAME.equals( navigablePath.getLocalName() )
|
||||||
|| modelPart.getNavigableRole() != null && isPartOfKey( modelPart.getNavigableRole() );
|
|
||||||
}
|
|
||||||
|
|
||||||
private static boolean isPartOfKey(NavigablePath navigablePath) {
|
|
||||||
return ForeignKeyDescriptor.PART_NAME.equals( navigablePath.getLocalName() )
|
|
||||||
|| ForeignKeyDescriptor.TARGET_PART_NAME.equals( navigablePath.getLocalName() )
|
|| ForeignKeyDescriptor.TARGET_PART_NAME.equals( navigablePath.getLocalName() )
|
||||||
|| navigablePath instanceof EntityIdentifierNavigablePath
|
|| navigablePath instanceof EntityIdentifierNavigablePath
|
||||||
|| navigablePath.getParent().getParent() != null && isPartOfKey( navigablePath.getParent() );
|
|| fetchParentAccess != null && fetchParentAccess.isEmbeddableInitializer()
|
||||||
}
|
&& ( (AbstractEmbeddableInitializer) fetchParentAccess ).isPartOfKey;
|
||||||
|
|
||||||
private static boolean isPartOfKey(NavigableRole navigableRole) {
|
|
||||||
final NavigableRole parent = navigableRole.getParent();
|
|
||||||
return parent != null
|
|
||||||
&& ( parent.getLocalName().equals( EntityIdentifierMapping.ID_ROLE_NAME ) || isPartOfKey( parent ) );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected DomainResultAssembler<?>[] createAssemblers(
|
protected DomainResultAssembler<?>[] createAssemblers(
|
||||||
|
@ -74,6 +74,7 @@ public void setUp(SessionFactoryScope scope) {
|
|||||||
public void tearDown(SessionFactoryScope scope) {
|
public void tearDown(SessionFactoryScope scope) {
|
||||||
scope.inTransaction(
|
scope.inTransaction(
|
||||||
session -> {
|
session -> {
|
||||||
|
session.createMutationQuery( "update EntityA a set a.componentA.entityA = null" ).executeUpdate();
|
||||||
session.createMutationQuery( "delete from EntityB" ).executeUpdate();
|
session.createMutationQuery( "delete from EntityB" ).executeUpdate();
|
||||||
session.createMutationQuery( "delete from EntityC" ).executeUpdate();
|
session.createMutationQuery( "delete from EntityC" ).executeUpdate();
|
||||||
session.createMutationQuery( "delete from EntityA" ).executeUpdate();
|
session.createMutationQuery( "delete from EntityA" ).executeUpdate();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user