Fix Polymorphic collection issue
This commit is contained in:
parent
0d024ffd59
commit
c2bb7d65f2
|
@ -54,7 +54,12 @@ public class EntityCollectionPart implements CollectionPart, EntityAssociationMa
|
||||||
Collection bootValueMapping,
|
Collection bootValueMapping,
|
||||||
String fkTargetModelPartName,
|
String fkTargetModelPartName,
|
||||||
MappingModelCreationProcess creationProcess) {
|
MappingModelCreationProcess creationProcess) {
|
||||||
fkTargetModelPart = entityMappingType.findSubPart( fkTargetModelPartName, null );
|
if ( fkTargetModelPartName == null ) {
|
||||||
|
fkTargetModelPart = entityMappingType.getIdentifierMapping();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
fkTargetModelPart = entityMappingType.findSubPart( fkTargetModelPartName, null );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -5128,19 +5128,33 @@ public abstract class AbstractEntityPersister
|
||||||
accessOptimizer.setPropertyValues( object, values );
|
accessOptimizer.setPropertyValues( object, values );
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
visitFetchables(
|
if ( hasSubclasses() ) {
|
||||||
fetchable -> {
|
visitAttributeMappings(
|
||||||
final AttributeMapping attribute = (AttributeMapping) fetchable;
|
attribute -> {
|
||||||
final int stateArrayPosition = ( (StateArrayContributorMapping) attribute ).getStateArrayPosition();
|
final int stateArrayPosition = ( (StateArrayContributorMapping) attribute ).getStateArrayPosition();
|
||||||
final Object value = values[stateArrayPosition];
|
final Object value = values[stateArrayPosition];
|
||||||
if ( value != UNFETCHED_PROPERTY ) {
|
if ( value != UNFETCHED_PROPERTY ) {
|
||||||
final Setter setter = attribute.getPropertyAccess().getSetter();
|
final Setter setter = attribute.getPropertyAccess().getSetter();
|
||||||
setter.set( object, value, getFactory() );
|
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 abstract class AbstractEntityPersister
|
||||||
private Map<String, AttributeMapping> declaredAttributeMappings = new LinkedHashMap<>();
|
private Map<String, AttributeMapping> declaredAttributeMappings = new LinkedHashMap<>();
|
||||||
private List<AttributeMapping> attributeMappings;
|
private List<AttributeMapping> attributeMappings;
|
||||||
protected List<Fetchable> staticFetchableList;
|
protected List<Fetchable> staticFetchableList;
|
||||||
|
protected int subtypesAttributeStateArrayStartingPosition;
|
||||||
|
|
||||||
protected ReflectionOptimizer.AccessOptimizer accessOptimizer;
|
protected ReflectionOptimizer.AccessOptimizer accessOptimizer;
|
||||||
|
|
||||||
|
@ -5777,6 +5792,7 @@ public abstract class AbstractEntityPersister
|
||||||
() -> {
|
() -> {
|
||||||
staticFetchableList = new ArrayList<>( attributeMappings.size() );
|
staticFetchableList = new ArrayList<>( attributeMappings.size() );
|
||||||
visitAttributeMappings( attributeMapping -> staticFetchableList.add( (Fetchable) attributeMapping ) );
|
visitAttributeMappings( attributeMapping -> staticFetchableList.add( (Fetchable) attributeMapping ) );
|
||||||
|
subtypesAttributeStateArrayStartingPosition = attributeMappings.size();
|
||||||
visitSubTypeAttributeMappings( attributeMapping -> staticFetchableList.add( (Fetchable) attributeMapping ) );
|
visitSubTypeAttributeMappings( attributeMapping -> staticFetchableList.add( (Fetchable) attributeMapping ) );
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,13 +48,10 @@ import org.hibernate.mapping.Selectable;
|
||||||
import org.hibernate.mapping.Subclass;
|
import org.hibernate.mapping.Subclass;
|
||||||
import org.hibernate.mapping.Table;
|
import org.hibernate.mapping.Table;
|
||||||
import org.hibernate.mapping.Value;
|
import org.hibernate.mapping.Value;
|
||||||
import org.hibernate.metamodel.mapping.AttributeMapping;
|
|
||||||
import org.hibernate.metamodel.mapping.EntityDiscriminatorMapping;
|
import org.hibernate.metamodel.mapping.EntityDiscriminatorMapping;
|
||||||
import org.hibernate.metamodel.mapping.JdbcMapping;
|
import org.hibernate.metamodel.mapping.JdbcMapping;
|
||||||
import org.hibernate.metamodel.mapping.StateArrayContributorMapping;
|
|
||||||
import org.hibernate.metamodel.mapping.internal.JoinedSubclassDiscriminatorMappingImpl;
|
import org.hibernate.metamodel.mapping.internal.JoinedSubclassDiscriminatorMappingImpl;
|
||||||
import org.hibernate.persister.spi.PersisterCreationContext;
|
import org.hibernate.persister.spi.PersisterCreationContext;
|
||||||
import org.hibernate.property.access.spi.Setter;
|
|
||||||
import org.hibernate.query.NavigablePath;
|
import org.hibernate.query.NavigablePath;
|
||||||
import org.hibernate.sql.CaseFragment;
|
import org.hibernate.sql.CaseFragment;
|
||||||
import org.hibernate.sql.InFragment;
|
import org.hibernate.sql.InFragment;
|
||||||
|
@ -1190,41 +1187,6 @@ public class JoinedSubclassEntityPersister extends AbstractEntityPersister {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@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
|
@Override
|
||||||
public TableGroup createRootTableGroup(
|
public TableGroup createRootTableGroup(
|
||||||
|
|
|
@ -41,10 +41,7 @@ import org.hibernate.mapping.Column;
|
||||||
import org.hibernate.mapping.PersistentClass;
|
import org.hibernate.mapping.PersistentClass;
|
||||||
import org.hibernate.mapping.Subclass;
|
import org.hibernate.mapping.Subclass;
|
||||||
import org.hibernate.mapping.Table;
|
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.persister.spi.PersisterCreationContext;
|
||||||
import org.hibernate.property.access.spi.Setter;
|
|
||||||
import org.hibernate.query.NavigablePath;
|
import org.hibernate.query.NavigablePath;
|
||||||
import org.hibernate.sql.SelectFragment;
|
import org.hibernate.sql.SelectFragment;
|
||||||
import org.hibernate.sql.ast.spi.SqlAliasBase;
|
import org.hibernate.sql.ast.spi.SqlAliasBase;
|
||||||
|
@ -301,42 +298,6 @@ public class UnionSubclassEntityPersister extends AbstractEntityPersister {
|
||||||
return false;
|
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
|
@Override
|
||||||
protected boolean shouldProcessSuperMapping() {
|
protected boolean shouldProcessSuperMapping() {
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -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<SuperType> 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<SuperType> 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<SuperType> getSuperTypes() {
|
||||||
|
return superTypes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSuperTypes(List<SuperType> superTypes) {
|
||||||
|
this.superTypes = superTypes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addSuperType(SuperType superType) {
|
||||||
|
if ( superTypes == null ) {
|
||||||
|
superTypes = new ArrayList<>();
|
||||||
|
}
|
||||||
|
this.superTypes.add( superType );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -87,13 +87,13 @@ public class SingleTableInheritanceTests {
|
||||||
assertThat( result, instanceOf( DomesticCustomer.class ) );
|
assertThat( result, instanceOf( DomesticCustomer.class ) );
|
||||||
final DomesticCustomer customer = (DomesticCustomer) result;
|
final DomesticCustomer customer = (DomesticCustomer) result;
|
||||||
assertThat( customer.getName(), is( "domestic" ) );
|
assertThat( customer.getName(), is( "domestic" ) );
|
||||||
assertThat( (customer).getTaxId(), is( "123" ) );
|
assertThat( customer.getTaxId(), is( "123" ) );
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
assertThat( result.getId(), is( 2 ) );
|
assertThat( result.getId(), is( 2 ) );
|
||||||
final ForeignCustomer customer = (ForeignCustomer) result;
|
final ForeignCustomer customer = (ForeignCustomer) result;
|
||||||
assertThat( customer.getName(), is( "foreign" ) );
|
assertThat( customer.getName(), is( "foreign" ) );
|
||||||
assertThat( (customer).getVat(), is( "987" ) );
|
assertThat( customer.getVat(), is( "987" ) );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue