diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/EntityCollectionPart.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/EntityCollectionPart.java index 03d3cfd77181..606784167bc9 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/EntityCollectionPart.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/EntityCollectionPart.java @@ -54,7 +54,12 @@ public void finishInitialization( Collection bootValueMapping, String fkTargetModelPartName, MappingModelCreationProcess creationProcess) { - fkTargetModelPart = entityMappingType.findSubPart( fkTargetModelPartName, null ); + if ( fkTargetModelPartName == null ) { + fkTargetModelPart = entityMappingType.getIdentifierMapping(); + } + else { + fkTargetModelPart = entityMappingType.findSubPart( fkTargetModelPartName, null ); + } } 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 e36ea47b175a..296fa5ca04b1 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 @@ -5128,19 +5128,33 @@ public void setPropertyValues(Object object, Object[] values) { accessOptimizer.setPropertyValues( object, values ); } else { - visitFetchables( - fetchable -> { - final AttributeMapping attribute = (AttributeMapping) fetchable; - final int stateArrayPosition = ( (StateArrayContributorMapping) attribute ).getStateArrayPosition(); - final Object value = values[stateArrayPosition]; - if ( value != UNFETCHED_PROPERTY ) { - final Setter setter = attribute.getPropertyAccess().getSetter(); - setter.set( object, value, getFactory() ); + if ( hasSubclasses() ) { + visitAttributeMappings( + attribute -> { + final int stateArrayPosition = ( (StateArrayContributorMapping) attribute ).getStateArrayPosition(); + final Object value = values[stateArrayPosition]; + if ( value != UNFETCHED_PROPERTY ) { + final Setter setter = attribute.getPropertyAccess().getSetter(); + setter.set( object, value, getFactory() ); + } } + ); + } + else { + visitFetchables( + fetchable -> { + final AttributeMapping attribute = (AttributeMapping) fetchable; + final int stateArrayPosition = ( (StateArrayContributorMapping) attribute ).getStateArrayPosition(); + final Object value = values[stateArrayPosition]; + if ( value != UNFETCHED_PROPERTY ) { + final Setter setter = attribute.getPropertyAccess().getSetter(); + setter.set( object, value, getFactory() ); + } - }, - null - ); + }, + null + ); + } } } @@ -5671,6 +5685,7 @@ public CacheEntry buildCacheEntry(Object entity, Object[] state, Object version, private Map declaredAttributeMappings = new LinkedHashMap<>(); private List attributeMappings; protected List staticFetchableList; + protected int subtypesAttributeStateArrayStartingPosition; protected ReflectionOptimizer.AccessOptimizer accessOptimizer; @@ -5777,6 +5792,7 @@ public void prepareMappingModel(MappingModelCreationProcess creationProcess) { () -> { staticFetchableList = new ArrayList<>( attributeMappings.size() ); visitAttributeMappings( attributeMapping -> staticFetchableList.add( (Fetchable) attributeMapping ) ); + subtypesAttributeStateArrayStartingPosition = attributeMappings.size(); visitSubTypeAttributeMappings( attributeMapping -> staticFetchableList.add( (Fetchable) attributeMapping ) ); return true; } diff --git a/hibernate-core/src/main/java/org/hibernate/persister/entity/JoinedSubclassEntityPersister.java b/hibernate-core/src/main/java/org/hibernate/persister/entity/JoinedSubclassEntityPersister.java index 7a634ef16a50..af2dfdaad922 100644 --- a/hibernate-core/src/main/java/org/hibernate/persister/entity/JoinedSubclassEntityPersister.java +++ b/hibernate-core/src/main/java/org/hibernate/persister/entity/JoinedSubclassEntityPersister.java @@ -48,13 +48,10 @@ import org.hibernate.mapping.Subclass; import org.hibernate.mapping.Table; import org.hibernate.mapping.Value; -import org.hibernate.metamodel.mapping.AttributeMapping; import org.hibernate.metamodel.mapping.EntityDiscriminatorMapping; import org.hibernate.metamodel.mapping.JdbcMapping; -import org.hibernate.metamodel.mapping.StateArrayContributorMapping; import org.hibernate.metamodel.mapping.internal.JoinedSubclassDiscriminatorMappingImpl; import org.hibernate.persister.spi.PersisterCreationContext; -import org.hibernate.property.access.spi.Setter; import org.hibernate.query.NavigablePath; import org.hibernate.sql.CaseFragment; import org.hibernate.sql.InFragment; @@ -1190,41 +1187,6 @@ public DomainResult createDomainResult( } } - @Override - public void setPropertyValues(Object object, Object[] values) { - if ( accessOptimizer != null ) { - accessOptimizer.setPropertyValues( object, values ); - } - else { - if ( hasSubclasses() ) { - visitAttributeMappings( - attribute -> { - final int stateArrayPosition = ( (StateArrayContributorMapping) attribute ).getStateArrayPosition(); - final Object value = values[stateArrayPosition]; - if ( value != UNFETCHED_PROPERTY ) { - final Setter setter = attribute.getPropertyAccess().getSetter(); - setter.set( object, value, getFactory() ); - } - } - ); - } - else { - visitFetchables( - fetchable -> { - final AttributeMapping attribute = (AttributeMapping) fetchable; - final int stateArrayPosition = ( (StateArrayContributorMapping) attribute ).getStateArrayPosition(); - final Object value = values[stateArrayPosition]; - if ( value != UNFETCHED_PROPERTY ) { - final Setter setter = attribute.getPropertyAccess().getSetter(); - setter.set( object, value, getFactory() ); - } - - }, - null - ); - } - } - } @Override public TableGroup createRootTableGroup( diff --git a/hibernate-core/src/main/java/org/hibernate/persister/entity/UnionSubclassEntityPersister.java b/hibernate-core/src/main/java/org/hibernate/persister/entity/UnionSubclassEntityPersister.java index 428f3f3469d8..a7a3102ee602 100644 --- a/hibernate-core/src/main/java/org/hibernate/persister/entity/UnionSubclassEntityPersister.java +++ b/hibernate-core/src/main/java/org/hibernate/persister/entity/UnionSubclassEntityPersister.java @@ -41,10 +41,7 @@ import org.hibernate.mapping.PersistentClass; import org.hibernate.mapping.Subclass; import org.hibernate.mapping.Table; -import org.hibernate.metamodel.mapping.AttributeMapping; -import org.hibernate.metamodel.mapping.StateArrayContributorMapping; import org.hibernate.persister.spi.PersisterCreationContext; -import org.hibernate.property.access.spi.Setter; import org.hibernate.query.NavigablePath; import org.hibernate.sql.SelectFragment; import org.hibernate.sql.ast.spi.SqlAliasBase; @@ -301,42 +298,6 @@ protected boolean isDiscriminatorFormula() { return false; } - @Override - public void setPropertyValues(Object object, Object[] values) { - if ( accessOptimizer != null ) { - accessOptimizer.setPropertyValues( object, values ); - } - else { - if ( hasSubclasses() ) { - visitAttributeMappings( - attribute -> { - final int stateArrayPosition = ( (StateArrayContributorMapping) attribute ).getStateArrayPosition(); - final Object value = values[stateArrayPosition]; - if ( value != UNFETCHED_PROPERTY ) { - final Setter setter = attribute.getPropertyAccess().getSetter(); - setter.set( object, value, getFactory() ); - } - } - ); - } - else { - visitFetchables( - fetchable -> { - final AttributeMapping attribute = (AttributeMapping) fetchable; - final int stateArrayPosition = ( (StateArrayContributorMapping) attribute ).getStateArrayPosition(); - final Object value = values[stateArrayPosition]; - if ( value != UNFETCHED_PROPERTY ) { - final Setter setter = attribute.getPropertyAccess().getSetter(); - setter.set( object, value, getFactory() ); - } - - }, - null - ); - } - } - } - @Override protected boolean shouldProcessSuperMapping() { return false; diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/metamodel/mapping/inheritance/OneToManyToInheritedTypeTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/metamodel/mapping/inheritance/OneToManyToInheritedTypeTest.java new file mode 100644 index 000000000000..9efbf45b8970 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/metamodel/mapping/inheritance/OneToManyToInheritedTypeTest.java @@ -0,0 +1,183 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html + */ +package org.hibernate.orm.test.metamodel.mapping.inheritance; + +import java.util.ArrayList; +import java.util.List; +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.OneToMany; + +import org.hibernate.testing.orm.junit.DomainModel; +import org.hibernate.testing.orm.junit.ServiceRegistry; +import org.hibernate.testing.orm.junit.SessionFactory; +import org.hibernate.testing.orm.junit.SessionFactoryScope; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static org.hamcrest.CoreMatchers.instanceOf; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.MatcherAssert.assertThat; + +/** + * @author Laurent Almeras + */ +@DomainModel( + annotatedClasses = { + OneToManyToInheritedTypeTest.SuperType.class, + OneToManyToInheritedTypeTest.TypeA.class, + OneToManyToInheritedTypeTest.TypeB.class, + OneToManyToInheritedTypeTest.LinkedEntity.class + } +) +@ServiceRegistry +@SessionFactory +public class OneToManyToInheritedTypeTest { + + @BeforeEach + public void setUp(SessionFactoryScope scope) { + scope.inTransaction( + session -> { + SuperType superType = new SuperType( 1 ); + TypeB typeB = new TypeB( 2, "typeB" ); + TypeA typeA = new TypeA( 3, "typeA" ); + LinkedEntity entity = new LinkedEntity( 3 ); + entity.addSuperType( superType ); + entity.addSuperType( typeB ); + entity.addSuperType( typeA ); + session.save( superType ); + session.save( typeB ); + session.save( typeA ); + session.save( entity ); + } + ); + } + + @Test + public void basicTest(SessionFactoryScope scope) { + scope.inTransaction( + session -> { + LinkedEntity entity = session.find( LinkedEntity.class, 3 ); + List superTypes = entity.getSuperTypes(); + assertThat( superTypes.size(), is( 3 ) ); + for ( SuperType superType : superTypes ) { + if ( superType.getId() == 2 ) { + assertThat( superType, instanceOf( TypeB.class ) ); + TypeB typeB = (TypeB) superType; + assertThat( typeB.getTypeBName(), is( "typeB" ) ); + } + if ( superType.getId() == 3 ) { + assertThat( superType, instanceOf( TypeA.class ) ); + TypeA typeB = (TypeA) superType; + assertThat( typeB.getTypeAName(), is( "typeA" ) ); + } + } + } + ); + } + + @Entity(name = "SuperType") + public static class SuperType { + private Integer id; + + public SuperType() { + } + + public SuperType(Integer id) { + this.id = id; + } + + @Id + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + } + + @Entity(name = "TypeA") + public static class TypeA extends SuperType { + private String typeAName; + + public TypeA() { + } + + public TypeA(Integer id, String typeAName) { + super( id ); + this.typeAName = typeAName; + } + + public String getTypeAName() { + return typeAName; + } + + public void setTypeAName(String typeAName) { + this.typeAName = typeAName; + } + } + + @Entity(name = "TypeB") + public static class TypeB extends SuperType { + private String typeBName; + + public TypeB() { + } + + public TypeB(Integer id, String typeBName) { + super( id ); + this.typeBName = typeBName; + } + + public String getTypeBName() { + return typeBName; + } + + public void setTypeBName(String typeBName) { + this.typeBName = typeBName; + } + } + + @Entity(name = "LinkedEntity") + public static class LinkedEntity { + private Integer id; + private List superTypes; + + public LinkedEntity() { + } + + public LinkedEntity(Integer id) { + this.id = id; + } + + @Id + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + @OneToMany + public List getSuperTypes() { + return superTypes; + } + + public void setSuperTypes(List superTypes) { + this.superTypes = superTypes; + } + + public void addSuperType(SuperType superType) { + if ( superTypes == null ) { + superTypes = new ArrayList<>(); + } + this.superTypes.add( superType ); + } + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/metamodel/mapping/inheritance/SingleTableInheritanceTests.java b/hibernate-core/src/test/java/org/hibernate/orm/test/metamodel/mapping/inheritance/SingleTableInheritanceTests.java index b39117e3f930..1b0e3cb0f10b 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/metamodel/mapping/inheritance/SingleTableInheritanceTests.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/metamodel/mapping/inheritance/SingleTableInheritanceTests.java @@ -87,13 +87,13 @@ public void rootQueryExecutionTest(SessionFactoryScope scope) { assertThat( result, instanceOf( DomesticCustomer.class ) ); final DomesticCustomer customer = (DomesticCustomer) result; assertThat( customer.getName(), is( "domestic" ) ); - assertThat( (customer).getTaxId(), is( "123" ) ); + assertThat( customer.getTaxId(), is( "123" ) ); } else { assertThat( result.getId(), is( 2 ) ); final ForeignCustomer customer = (ForeignCustomer) result; assertThat( customer.getName(), is( "foreign" ) ); - assertThat( (customer).getVat(), is( "987" ) ); + assertThat( customer.getVat(), is( "987" ) ); } }