Fix Polymorphic collection issue

This commit is contained in:
Andrea Boriero 2020-01-13 11:36:40 +00:00
parent 0d024ffd59
commit c2bb7d65f2
6 changed files with 218 additions and 91 deletions

View File

@ -54,8 +54,13 @@ public class EntityCollectionPart implements CollectionPart, EntityAssociationMa
Collection bootValueMapping, Collection bootValueMapping,
String fkTargetModelPartName, String fkTargetModelPartName,
MappingModelCreationProcess creationProcess) { MappingModelCreationProcess creationProcess) {
if ( fkTargetModelPartName == null ) {
fkTargetModelPart = entityMappingType.getIdentifierMapping();
}
else {
fkTargetModelPart = entityMappingType.findSubPart( fkTargetModelPartName, null ); fkTargetModelPart = entityMappingType.findSubPart( fkTargetModelPartName, null );
} }
}
@Override @Override

View File

@ -5127,6 +5127,19 @@ public abstract class AbstractEntityPersister
if ( accessOptimizer != null ) { if ( accessOptimizer != null ) {
accessOptimizer.setPropertyValues( object, values ); 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 { else {
visitFetchables( visitFetchables(
fetchable -> { fetchable -> {
@ -5143,6 +5156,7 @@ public abstract class AbstractEntityPersister
); );
} }
} }
}
public void setPropertyValue(Object object, int i, Object value) { public void setPropertyValue(Object object, int i, Object value) {
final String propertyName = getPropertyNames()[i]; final String propertyName = getPropertyNames()[i];
@ -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;
} }

View File

@ -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(

View File

@ -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;

View File

@ -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 );
}
}
}

View File

@ -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" ) );
} }
} }