Fix ToOneAttributeMapping bidirectionalAttributeName value determination
This commit is contained in:
parent
71204a9e97
commit
7dc70e9350
|
@ -31,6 +31,7 @@ import org.hibernate.mapping.PersistentClass;
|
||||||
import org.hibernate.mapping.Property;
|
import org.hibernate.mapping.Property;
|
||||||
import org.hibernate.mapping.Selectable;
|
import org.hibernate.mapping.Selectable;
|
||||||
import org.hibernate.mapping.ToOne;
|
import org.hibernate.mapping.ToOne;
|
||||||
|
import org.hibernate.mapping.Value;
|
||||||
import org.hibernate.metamodel.mapping.AssociationKey;
|
import org.hibernate.metamodel.mapping.AssociationKey;
|
||||||
import org.hibernate.metamodel.mapping.CollectionPart;
|
import org.hibernate.metamodel.mapping.CollectionPart;
|
||||||
import org.hibernate.metamodel.mapping.EmbeddableValuedModelPart;
|
import org.hibernate.metamodel.mapping.EmbeddableValuedModelPart;
|
||||||
|
@ -236,7 +237,10 @@ public class ToOneAttributeMapping
|
||||||
final Iterator<Property> propertyClosureIterator = entityBinding.getPropertyClosureIterator();
|
final Iterator<Property> propertyClosureIterator = entityBinding.getPropertyClosureIterator();
|
||||||
while ( propertyClosureIterator.hasNext() ) {
|
while ( propertyClosureIterator.hasNext() ) {
|
||||||
final Property property = propertyClosureIterator.next();
|
final Property property = propertyClosureIterator.next();
|
||||||
if ( property.getValue() instanceof OneToOne && name.equals( ( (OneToOne) property.getValue() ).getMappedByProperty() ) ) {
|
if ( property.getValue() instanceof OneToOne
|
||||||
|
&& name.equals( ( (OneToOne) property.getValue() ).getMappedByProperty() )
|
||||||
|
&& ( (OneToOne) property.getValue() ).getReferencedEntityName().equals(
|
||||||
|
declaringType.getJavaTypeDescriptor().getJavaType().getTypeName() ) ) {
|
||||||
bidirectionalAttributeName = property.getName();
|
bidirectionalAttributeName = property.getName();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -247,7 +251,11 @@ public class ToOneAttributeMapping
|
||||||
final Iterator<Property> propertyClosureIterator = entityBinding.getPropertyClosureIterator();
|
final Iterator<Property> propertyClosureIterator = entityBinding.getPropertyClosureIterator();
|
||||||
while ( propertyClosureIterator.hasNext() ) {
|
while ( propertyClosureIterator.hasNext() ) {
|
||||||
final Property property = propertyClosureIterator.next();
|
final Property property = propertyClosureIterator.next();
|
||||||
if ( property.getValue() instanceof Collection && name.equals( ( (Collection) property.getValue() ).getMappedByProperty() ) ) {
|
final Value value = property.getValue();
|
||||||
|
if ( value instanceof Collection
|
||||||
|
&& name.equals( ( (Collection) value ).getMappedByProperty() )
|
||||||
|
&& ( (Collection) value ).getElement().getType().getName()
|
||||||
|
.equals( declaringType.getJavaTypeDescriptor().getJavaType().getTypeName() ) ) {
|
||||||
bidirectionalAttributeName = property.getName();
|
bidirectionalAttributeName = property.getName();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -1046,6 +1054,7 @@ public class ToOneAttributeMapping
|
||||||
final ModelPart bidirectionalModelPart = entityMappingType.findSubPart( bidirectionalAttributeName );
|
final ModelPart bidirectionalModelPart = entityMappingType.findSubPart( bidirectionalAttributeName );
|
||||||
// Add the inverse association key side as well to be able to resolve to a CircularFetch
|
// Add the inverse association key side as well to be able to resolve to a CircularFetch
|
||||||
if ( bidirectionalModelPart instanceof ToOneAttributeMapping ) {
|
if ( bidirectionalModelPart instanceof ToOneAttributeMapping ) {
|
||||||
|
assert bidirectionalModelPart.getPartMappingType() == declaringTableGroupProducer;
|
||||||
final ToOneAttributeMapping bidirectionalAttribute = (ToOneAttributeMapping) bidirectionalModelPart;
|
final ToOneAttributeMapping bidirectionalAttribute = (ToOneAttributeMapping) bidirectionalModelPart;
|
||||||
final AssociationKey secondKey = bidirectionalAttribute.getForeignKeyDescriptor().getAssociationKey();
|
final AssociationKey secondKey = bidirectionalAttribute.getForeignKeyDescriptor().getAssociationKey();
|
||||||
if ( creationState.registerVisitedAssociationKey( secondKey ) ) {
|
if ( creationState.registerVisitedAssociationKey( secondKey ) ) {
|
||||||
|
|
|
@ -15,6 +15,7 @@ import org.hibernate.PropertyAccessException;
|
||||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||||
import org.hibernate.internal.util.ReflectHelper;
|
import org.hibernate.internal.util.ReflectHelper;
|
||||||
import org.hibernate.property.access.internal.AbstractFieldSerialForm;
|
import org.hibernate.property.access.internal.AbstractFieldSerialForm;
|
||||||
|
import org.hibernate.proxy.HibernateProxy;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Field-based implementation of Setter
|
* Field-based implementation of Setter
|
||||||
|
@ -67,15 +68,19 @@ public class SetterFieldImpl implements Setter {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
final String valueType;
|
||||||
|
if ( value instanceof HibernateProxy ) {
|
||||||
|
valueType = ( (HibernateProxy) value ).getHibernateLazyInitializer().getEntityName();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
valueType = value.getClass().getTypeName();
|
||||||
|
}
|
||||||
throw new PropertyAccessException(
|
throw new PropertyAccessException(
|
||||||
e,
|
e,
|
||||||
String.format(
|
String.format(
|
||||||
Locale.ROOT,
|
Locale.ROOT,
|
||||||
"Could not set value [%s (`%s`)] by reflection",
|
"Could not set value of type [%s]",
|
||||||
value,
|
valueType
|
||||||
value == null ? "<null>" : value.getClass().getTypeName(),
|
|
||||||
containerClass == null ? "<dynamic>" : containerClass.getTypeName(),
|
|
||||||
propertyName
|
|
||||||
),
|
),
|
||||||
true,
|
true,
|
||||||
containerClass,
|
containerClass,
|
||||||
|
|
|
@ -8,7 +8,6 @@ package org.hibernate.sql.results.graph;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.hibernate.NotYetImplementedFor6Exception;
|
|
||||||
import org.hibernate.metamodel.mapping.AssociationKey;
|
import org.hibernate.metamodel.mapping.AssociationKey;
|
||||||
import org.hibernate.metamodel.mapping.ForeignKeyDescriptor;
|
import org.hibernate.metamodel.mapping.ForeignKeyDescriptor;
|
||||||
import org.hibernate.metamodel.mapping.ModelPart;
|
import org.hibernate.metamodel.mapping.ModelPart;
|
||||||
|
@ -50,9 +49,7 @@ public interface DomainResultCreationState {
|
||||||
* Resolve the ModelPart associated with a given NavigablePath. More specific ModelParts should be preferred - e.g.
|
* Resolve the ModelPart associated with a given NavigablePath. More specific ModelParts should be preferred - e.g.
|
||||||
* the SingularAssociationAttributeMapping rather than just the EntityTypeMapping for the associated type
|
* the SingularAssociationAttributeMapping rather than just the EntityTypeMapping for the associated type
|
||||||
*/
|
*/
|
||||||
default ModelPart resolveModelPart(NavigablePath navigablePath) {
|
ModelPart resolveModelPart(NavigablePath navigablePath);
|
||||||
throw new NotYetImplementedFor6Exception( getClass() );
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Visit fetches for the given parent.
|
* Visit fetches for the given parent.
|
||||||
|
|
|
@ -6,8 +6,11 @@
|
||||||
*/
|
*/
|
||||||
package org.hibernate.orm.test.loading;
|
package org.hibernate.orm.test.loading;
|
||||||
|
|
||||||
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
import org.hibernate.testing.orm.junit.DomainModel;
|
||||||
import org.junit.Test;
|
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 jakarta.persistence.Entity;
|
import jakarta.persistence.Entity;
|
||||||
import jakarta.persistence.Id;
|
import jakarta.persistence.Id;
|
||||||
|
@ -15,16 +18,19 @@ import jakarta.persistence.OneToOne;
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
public class LoadContainedInDoubleContainingTest extends BaseCoreFunctionalTestCase {
|
@DomainModel(
|
||||||
|
annotatedClasses = {
|
||||||
@Override
|
LoadContainedInDoubleContainingTest.Containing.class,
|
||||||
protected Class<?>[] getAnnotatedClasses() {
|
LoadContainedInDoubleContainingTest.OtherContained.class,
|
||||||
return new Class[] { Containing.class, OtherContained.class, Contained.class };
|
LoadContainedInDoubleContainingTest.Contained.class
|
||||||
}
|
}
|
||||||
|
)
|
||||||
|
@SessionFactory
|
||||||
|
public class LoadContainedInDoubleContainingTest {
|
||||||
|
|
||||||
@Test
|
@BeforeEach
|
||||||
public void test() {
|
public void setUp(SessionFactoryScope scope) {
|
||||||
inTransaction( session -> {
|
scope.inTransaction( session -> {
|
||||||
Containing containing = new Containing( 1, "initial" );
|
Containing containing = new Containing( 1, "initial" );
|
||||||
OtherContained otherContained = new OtherContained( 2, "initial" );
|
OtherContained otherContained = new OtherContained( 2, "initial" );
|
||||||
containing.setOtherContained( otherContained );
|
containing.setOtherContained( otherContained );
|
||||||
|
@ -32,19 +38,20 @@ public class LoadContainedInDoubleContainingTest extends BaseCoreFunctionalTestC
|
||||||
session.persist( containing );
|
session.persist( containing );
|
||||||
session.persist( otherContained );
|
session.persist( otherContained );
|
||||||
} );
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
inTransaction( session -> {
|
@Test
|
||||||
OtherContained entity = session.load( OtherContained.class, 2 );
|
public void test(SessionFactoryScope scope) {
|
||||||
String text = entity.getText();
|
scope.inTransaction( session -> {
|
||||||
|
OtherContained otherContained = session.load( OtherContained.class, 2 );
|
||||||
|
String text = otherContained.getText();
|
||||||
assertThat( text ).isEqualTo( "initial" );
|
assertThat( text ).isEqualTo( "initial" );
|
||||||
} );
|
} );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Entity(name = Containing.NAME)
|
@Entity(name = "Containing")
|
||||||
public static class Containing {
|
public static class Containing {
|
||||||
|
|
||||||
static final String NAME = "Containing";
|
|
||||||
|
|
||||||
@Id
|
@Id
|
||||||
private Integer id;
|
private Integer id;
|
||||||
private String text;
|
private String text;
|
||||||
|
@ -69,34 +76,39 @@ public class LoadContainedInDoubleContainingTest extends BaseCoreFunctionalTestC
|
||||||
public Integer getId() {
|
public Integer getId() {
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setId(Integer id) {
|
public void setId(Integer id) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getText() {
|
public String getText() {
|
||||||
return text;
|
return text;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setText(String text) {
|
public void setText(String text) {
|
||||||
this.text = text;
|
this.text = text;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Contained getContained() {
|
public Contained getContained() {
|
||||||
return contained;
|
return contained;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setContained(Contained contained) {
|
public void setContained(Contained contained) {
|
||||||
this.contained = contained;
|
this.contained = contained;
|
||||||
}
|
}
|
||||||
|
|
||||||
public OtherContained getOtherContained() {
|
public OtherContained getOtherContained() {
|
||||||
return otherContained;
|
return otherContained;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setOtherContained(OtherContained otherContained) {
|
public void setOtherContained(OtherContained otherContained) {
|
||||||
this.otherContained = otherContained;
|
this.otherContained = otherContained;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Entity(name = Contained.NAME)
|
@Entity(name = "Contained")
|
||||||
public static class Contained {
|
public static class Contained {
|
||||||
|
|
||||||
static final String NAME = "Contained";
|
|
||||||
|
|
||||||
@Id
|
@Id
|
||||||
private Integer id;
|
private Integer id;
|
||||||
private String text;
|
private String text;
|
||||||
|
@ -115,28 +127,31 @@ public class LoadContainedInDoubleContainingTest extends BaseCoreFunctionalTestC
|
||||||
public Integer getId() {
|
public Integer getId() {
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setId(Integer id) {
|
public void setId(Integer id) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getText() {
|
public String getText() {
|
||||||
return text;
|
return text;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setText(String text) {
|
public void setText(String text) {
|
||||||
this.text = text;
|
this.text = text;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Containing getContaining() {
|
public Containing getContaining() {
|
||||||
return containing;
|
return containing;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setContaining(Containing containing) {
|
public void setContaining(Containing containing) {
|
||||||
this.containing = containing;
|
this.containing = containing;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Entity(name = OtherContained.NAME)
|
@Entity(name = "OtherContained")
|
||||||
public static class OtherContained {
|
public static class OtherContained {
|
||||||
|
|
||||||
static final String NAME = "OtherContained";
|
|
||||||
|
|
||||||
@Id
|
@Id
|
||||||
private Integer id;
|
private Integer id;
|
||||||
private String text;
|
private String text;
|
||||||
|
@ -155,18 +170,23 @@ public class LoadContainedInDoubleContainingTest extends BaseCoreFunctionalTestC
|
||||||
public Integer getId() {
|
public Integer getId() {
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setId(Integer id) {
|
public void setId(Integer id) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getText() {
|
public String getText() {
|
||||||
return text;
|
return text;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setText(String text) {
|
public void setText(String text) {
|
||||||
this.text = text;
|
this.text = text;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Containing getContaining() {
|
public Containing getContaining() {
|
||||||
return containing;
|
return containing;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setContaining(Containing containing) {
|
public void setContaining(Containing containing) {
|
||||||
this.containing = containing;
|
this.containing = containing;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue