Fix loading OnetoOne self referencing entity
This commit is contained in:
parent
aded53a760
commit
d21db9e807
|
@ -148,8 +148,13 @@ public class LoaderSqlAstCreationState
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void registerVisitedAssociationKey(AssociationKey associationKey) {
|
public boolean registerVisitedAssociationKey(AssociationKey associationKey) {
|
||||||
visitedAssociationKeys.add( associationKey );
|
return visitedAssociationKeys.add( associationKey );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void removeVisitedAssociationKey(AssociationKey associationKey) {
|
||||||
|
visitedAssociationKeys.remove( associationKey );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -425,10 +425,21 @@ public class EntityCollectionPart
|
||||||
boolean selected,
|
boolean selected,
|
||||||
String resultVariable,
|
String resultVariable,
|
||||||
DomainResultCreationState creationState) {
|
DomainResultCreationState creationState) {
|
||||||
creationState.registerVisitedAssociationKey( getForeignKeyDescriptor().getAssociationKey() );
|
final boolean added = creationState.registerVisitedAssociationKey( getForeignKeyDescriptor().getAssociationKey() );
|
||||||
|
|
||||||
final TableGroup partTableGroup = resolveTableGroup( fetchablePath, creationState );
|
final TableGroup partTableGroup = resolveTableGroup( fetchablePath, creationState );
|
||||||
return new EntityFetchJoinedImpl( fetchParent, this, partTableGroup, selected, fetchablePath, creationState );
|
final EntityFetchJoinedImpl fetch = new EntityFetchJoinedImpl(
|
||||||
|
fetchParent,
|
||||||
|
this,
|
||||||
|
partTableGroup,
|
||||||
|
selected,
|
||||||
|
fetchablePath,
|
||||||
|
creationState
|
||||||
|
);
|
||||||
|
if ( added ) {
|
||||||
|
creationState.removeVisitedAssociationKey( getForeignKeyDescriptor().getAssociationKey() );
|
||||||
|
}
|
||||||
|
return fetch;
|
||||||
}
|
}
|
||||||
|
|
||||||
private TableGroup resolveTableGroup(NavigablePath fetchablePath, DomainResultCreationState creationState) {
|
private TableGroup resolveTableGroup(NavigablePath fetchablePath, DomainResultCreationState creationState) {
|
||||||
|
|
|
@ -378,26 +378,37 @@ public class PluralAttributeMappingImpl
|
||||||
DomainResultCreationState creationState) {
|
DomainResultCreationState creationState) {
|
||||||
final SqlAstCreationState sqlAstCreationState = creationState.getSqlAstCreationState();
|
final SqlAstCreationState sqlAstCreationState = creationState.getSqlAstCreationState();
|
||||||
|
|
||||||
creationState.registerVisitedAssociationKey( fkDescriptor.getAssociationKey() );
|
final boolean added = creationState.registerVisitedAssociationKey( fkDescriptor.getAssociationKey() );
|
||||||
|
|
||||||
if ( fetchTiming == FetchTiming.IMMEDIATE ) {
|
try {
|
||||||
if ( selected ) {
|
if ( fetchTiming == FetchTiming.IMMEDIATE ) {
|
||||||
final TableGroup collectionTableGroup = resolveCollectionTableGroup(
|
if ( selected ) {
|
||||||
fetchParent,
|
final TableGroup collectionTableGroup = resolveCollectionTableGroup(
|
||||||
fetchablePath,
|
fetchParent,
|
||||||
creationState,
|
fetchablePath,
|
||||||
sqlAstCreationState
|
creationState,
|
||||||
);
|
sqlAstCreationState
|
||||||
|
);
|
||||||
|
|
||||||
return new EagerCollectionFetch(
|
return new EagerCollectionFetch(
|
||||||
fetchablePath,
|
fetchablePath,
|
||||||
this,
|
this,
|
||||||
collectionTableGroup,
|
collectionTableGroup,
|
||||||
fetchParent,
|
fetchParent,
|
||||||
creationState
|
creationState
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return createSelectEagerCollectionFetch(
|
||||||
|
fetchParent,
|
||||||
|
fetchablePath,
|
||||||
|
creationState,
|
||||||
|
sqlAstCreationState
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
|
if ( getCollectionDescriptor().getCollectionType().hasHolder() ) {
|
||||||
return createSelectEagerCollectionFetch(
|
return createSelectEagerCollectionFetch(
|
||||||
fetchParent,
|
fetchParent,
|
||||||
fetchablePath,
|
fetchablePath,
|
||||||
|
@ -405,13 +416,16 @@ public class PluralAttributeMappingImpl
|
||||||
sqlAstCreationState
|
sqlAstCreationState
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if ( getCollectionDescriptor().getCollectionType().hasHolder() ) {
|
return createDelayedCollectionFetch( fetchParent, fetchablePath, creationState, sqlAstCreationState );
|
||||||
return createSelectEagerCollectionFetch( fetchParent, fetchablePath, creationState, sqlAstCreationState );
|
}
|
||||||
|
finally {
|
||||||
|
// This is only necessary because the association key is too general i.e. also matching FKs that other associations would match
|
||||||
|
// and on top of this, we are not handling circular fetches for plural attributes yet
|
||||||
|
if ( added ) {
|
||||||
|
creationState.removeVisitedAssociationKey( fkDescriptor.getAssociationKey() );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return createDelayedCollectionFetch( fetchParent, fetchablePath, creationState, sqlAstCreationState );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private Fetch createSelectEagerCollectionFetch(
|
private Fetch createSelectEagerCollectionFetch(
|
||||||
|
|
|
@ -572,9 +572,15 @@ public class ToOneAttributeMapping
|
||||||
public void setForeignKeyDescriptor(ForeignKeyDescriptor foreignKeyDescriptor) {
|
public void setForeignKeyDescriptor(ForeignKeyDescriptor foreignKeyDescriptor) {
|
||||||
assert identifyingColumnsTableExpression != null;
|
assert identifyingColumnsTableExpression != null;
|
||||||
this.foreignKeyDescriptor = foreignKeyDescriptor;
|
this.foreignKeyDescriptor = foreignKeyDescriptor;
|
||||||
this.sideNature = foreignKeyDescriptor.getAssociationKey().getTable().equals( identifyingColumnsTableExpression )
|
if ( cardinality == Cardinality.ONE_TO_ONE && bidirectionalAttributeName != null ) {
|
||||||
? ForeignKeyDescriptor.Nature.KEY
|
this.sideNature = ForeignKeyDescriptor.Nature.TARGET;
|
||||||
: ForeignKeyDescriptor.Nature.TARGET;
|
}
|
||||||
|
else {
|
||||||
|
this.sideNature = foreignKeyDescriptor.getAssociationKey().getTable().equals(
|
||||||
|
identifyingColumnsTableExpression )
|
||||||
|
? ForeignKeyDescriptor.Nature.KEY
|
||||||
|
: ForeignKeyDescriptor.Nature.TARGET;
|
||||||
|
}
|
||||||
|
|
||||||
// We can only use the parent table group if the FK is located there and ignoreNotFound is false
|
// We can only use the parent table group if the FK is located there and ignoreNotFound is false
|
||||||
// If this is not the case, the FK is not constrained or on a join/secondary table, so we need a join
|
// If this is not the case, the FK is not constrained or on a join/secondary table, so we need a join
|
||||||
|
@ -738,36 +744,35 @@ public class ToOneAttributeMapping
|
||||||
|
|
||||||
We have a circularity but it is not bidirectional
|
We have a circularity but it is not bidirectional
|
||||||
*/
|
*/
|
||||||
if ( sideNature == ForeignKeyDescriptor.Nature.KEY ) {
|
final TableGroup parentTableGroup = creationState
|
||||||
final TableGroup parentTableGroup = creationState
|
.getSqlAstCreationState()
|
||||||
.getSqlAstCreationState()
|
.getFromClauseAccess()
|
||||||
.getFromClauseAccess()
|
.getTableGroup( fetchParent.getNavigablePath() );
|
||||||
.getTableGroup( fetchParent.getNavigablePath() );
|
final DomainResult<?> foreignKeyDomainResult;
|
||||||
final DomainResult<?> foreignKeyDomainResult;
|
assert !creationState.isResolvingCircularFetch();
|
||||||
assert !creationState.isResolvingCircularFetch();
|
try {
|
||||||
try {
|
creationState.setResolvingCircularFetch( true );
|
||||||
creationState.setResolvingCircularFetch( true );
|
foreignKeyDomainResult = foreignKeyDescriptor.createDomainResult(
|
||||||
foreignKeyDomainResult = foreignKeyDescriptor.createKeyDomainResult(
|
|
||||||
fetchablePath,
|
|
||||||
parentTableGroup,
|
|
||||||
creationState
|
|
||||||
);
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
creationState.setResolvingCircularFetch( false );
|
|
||||||
}
|
|
||||||
return new CircularFetchImpl(
|
|
||||||
this,
|
|
||||||
getEntityMappingType(),
|
|
||||||
fetchTiming,
|
|
||||||
fetchablePath,
|
fetchablePath,
|
||||||
fetchParent,
|
parentTableGroup,
|
||||||
this,
|
sideNature,
|
||||||
isSelectByUniqueKey( sideNature ),
|
creationState
|
||||||
fetchablePath,
|
|
||||||
foreignKeyDomainResult
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
finally {
|
||||||
|
creationState.setResolvingCircularFetch( false );
|
||||||
|
}
|
||||||
|
return new CircularFetchImpl(
|
||||||
|
this,
|
||||||
|
getEntityMappingType(),
|
||||||
|
fetchTiming,
|
||||||
|
fetchablePath,
|
||||||
|
fetchParent,
|
||||||
|
this,
|
||||||
|
isSelectByUniqueKey( sideNature ),
|
||||||
|
fetchablePath,
|
||||||
|
foreignKeyDomainResult
|
||||||
|
);
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -998,6 +1003,7 @@ public class ToOneAttributeMapping
|
||||||
|| fetchParent.getNavigablePath() instanceof TreatedNavigablePath
|
|| fetchParent.getNavigablePath() instanceof TreatedNavigablePath
|
||||||
&& parentNavigablePath.equals( fetchParent.getNavigablePath().getRealParent() );
|
&& parentNavigablePath.equals( fetchParent.getNavigablePath().getRealParent() );
|
||||||
|
|
||||||
|
|
||||||
if ( fetchTiming == FetchTiming.IMMEDIATE && selected ) {
|
if ( fetchTiming == FetchTiming.IMMEDIATE && selected ) {
|
||||||
final TableGroup tableGroup;
|
final TableGroup tableGroup;
|
||||||
if ( fetchParent instanceof EntityResultJoinedSubclassImpl &&
|
if ( fetchParent instanceof EntityResultJoinedSubclassImpl &&
|
||||||
|
@ -1034,15 +1040,17 @@ public class ToOneAttributeMapping
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
creationState.registerVisitedAssociationKey( foreignKeyDescriptor.getAssociationKey() );
|
final boolean added = creationState.registerVisitedAssociationKey( foreignKeyDescriptor.getAssociationKey() );
|
||||||
|
AssociationKey additionalAssociationKey = null;
|
||||||
if ( cardinality == Cardinality.LOGICAL_ONE_TO_ONE && bidirectionalAttributeName != null ) {
|
if ( cardinality == Cardinality.LOGICAL_ONE_TO_ONE && bidirectionalAttributeName != null ) {
|
||||||
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 ) {
|
||||||
final ToOneAttributeMapping bidirectionalAttribute = (ToOneAttributeMapping) bidirectionalModelPart;
|
final ToOneAttributeMapping bidirectionalAttribute = (ToOneAttributeMapping) bidirectionalModelPart;
|
||||||
creationState.registerVisitedAssociationKey(
|
final AssociationKey secondKey = bidirectionalAttribute.getForeignKeyDescriptor().getAssociationKey();
|
||||||
bidirectionalAttribute.getForeignKeyDescriptor().getAssociationKey()
|
if ( creationState.registerVisitedAssociationKey( secondKey ) ) {
|
||||||
);
|
additionalAssociationKey = secondKey;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
final EntityFetchJoinedImpl entityFetchJoined = new EntityFetchJoinedImpl(
|
final EntityFetchJoinedImpl entityFetchJoined = new EntityFetchJoinedImpl(
|
||||||
|
@ -1053,6 +1061,12 @@ public class ToOneAttributeMapping
|
||||||
fetchablePath,
|
fetchablePath,
|
||||||
creationState
|
creationState
|
||||||
);
|
);
|
||||||
|
if ( added ) {
|
||||||
|
creationState.removeVisitedAssociationKey( foreignKeyDescriptor.getAssociationKey() );
|
||||||
|
}
|
||||||
|
if ( additionalAssociationKey != null ) {
|
||||||
|
creationState.removeVisitedAssociationKey( additionalAssociationKey );
|
||||||
|
}
|
||||||
return entityFetchJoined;
|
return entityFetchJoined;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -175,7 +175,8 @@ public class DomainResultCreationStateImpl
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void registerVisitedAssociationKey(AssociationKey associationKey) {
|
public boolean registerVisitedAssociationKey(AssociationKey associationKey) {
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -31,7 +31,11 @@ public interface DomainResultCreationState {
|
||||||
return (SqlAliasBaseManager) getSqlAstCreationState().getSqlAliasBaseGenerator();
|
return (SqlAliasBaseManager) getSqlAstCreationState().getSqlAliasBaseGenerator();
|
||||||
}
|
}
|
||||||
|
|
||||||
default void registerVisitedAssociationKey(AssociationKey associationKey){
|
default boolean registerVisitedAssociationKey(AssociationKey associationKey) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
default void removeVisitedAssociationKey(AssociationKey associationKey){
|
||||||
}
|
}
|
||||||
|
|
||||||
default boolean isAssociationKeyVisited(AssociationKey associationKey){
|
default boolean isAssociationKeyVisited(AssociationKey associationKey){
|
||||||
|
|
|
@ -24,6 +24,7 @@ import jakarta.persistence.Embeddable;
|
||||||
import jakarta.persistence.Embedded;
|
import jakarta.persistence.Embedded;
|
||||||
import jakarta.persistence.EmbeddedId;
|
import jakarta.persistence.EmbeddedId;
|
||||||
import jakarta.persistence.Entity;
|
import jakarta.persistence.Entity;
|
||||||
|
import jakarta.persistence.FetchType;
|
||||||
import jakarta.persistence.ForeignKey;
|
import jakarta.persistence.ForeignKey;
|
||||||
import jakarta.persistence.GeneratedValue;
|
import jakarta.persistence.GeneratedValue;
|
||||||
import jakarta.persistence.GenerationType;
|
import jakarta.persistence.GenerationType;
|
||||||
|
@ -252,7 +253,7 @@ public class ForeignKeyConstraintTest {
|
||||||
@jakarta.persistence.Column( name = "MATRICULATION_NUMBER" )
|
@jakarta.persistence.Column( name = "MATRICULATION_NUMBER" )
|
||||||
public String matriculationNumber;
|
public String matriculationNumber;
|
||||||
|
|
||||||
@ManyToOne
|
@ManyToOne(fetch = FetchType.LAZY)
|
||||||
@JoinColumns(
|
@JoinColumns(
|
||||||
value = {
|
value = {
|
||||||
@JoinColumn( name = "CAR_NR", referencedColumnName = "CAR_NR" ),
|
@JoinColumn( name = "CAR_NR", referencedColumnName = "CAR_NR" ),
|
||||||
|
@ -262,7 +263,7 @@ public class ForeignKeyConstraintTest {
|
||||||
)
|
)
|
||||||
public Car car;
|
public Car car;
|
||||||
|
|
||||||
@ManyToOne
|
@ManyToOne(fetch = FetchType.LAZY)
|
||||||
@JoinColumns(
|
@JoinColumns(
|
||||||
value = {
|
value = {
|
||||||
@JoinColumn( name = "CAR_NR2", referencedColumnName = "CAR_NR" ),
|
@JoinColumn( name = "CAR_NR2", referencedColumnName = "CAR_NR" ),
|
||||||
|
@ -272,7 +273,7 @@ public class ForeignKeyConstraintTest {
|
||||||
)
|
)
|
||||||
public Car car2;
|
public Car car2;
|
||||||
|
|
||||||
@OneToOne
|
@OneToOne(fetch = FetchType.LAZY)
|
||||||
@JoinColumns(
|
@JoinColumns(
|
||||||
value = {
|
value = {
|
||||||
@JoinColumn( name = "CAR_NR3", referencedColumnName = "CAR_NR" ),
|
@JoinColumn( name = "CAR_NR3", referencedColumnName = "CAR_NR" ),
|
||||||
|
@ -282,7 +283,7 @@ public class ForeignKeyConstraintTest {
|
||||||
)
|
)
|
||||||
public Car car3;
|
public Car car3;
|
||||||
|
|
||||||
@OneToOne
|
@OneToOne(fetch = FetchType.LAZY)
|
||||||
@JoinColumns(
|
@JoinColumns(
|
||||||
value = {
|
value = {
|
||||||
@JoinColumn( name = "CAR_NR4", referencedColumnName = "CAR_NR" ),
|
@JoinColumn( name = "CAR_NR4", referencedColumnName = "CAR_NR" ),
|
||||||
|
@ -372,19 +373,19 @@ public class ForeignKeyConstraintTest {
|
||||||
|
|
||||||
public String color;
|
public String color;
|
||||||
|
|
||||||
@ManyToOne
|
@ManyToOne(fetch = FetchType.LAZY)
|
||||||
@JoinColumn( name = "OWNER_PERSON_ID", foreignKey = @ForeignKey( name = "FK_CAR_OWNER") )
|
@JoinColumn( name = "OWNER_PERSON_ID", foreignKey = @ForeignKey( name = "FK_CAR_OWNER") )
|
||||||
public Person owner;
|
public Person owner;
|
||||||
|
|
||||||
@ManyToOne
|
@ManyToOne(fetch = FetchType.LAZY)
|
||||||
@JoinColumn( name = "OWNER_PERSON_ID2", foreignKey = @ForeignKey( name = "FK_CAR_OWNER2", value = ConstraintMode.NO_CONSTRAINT ) )
|
@JoinColumn( name = "OWNER_PERSON_ID2", foreignKey = @ForeignKey( name = "FK_CAR_OWNER2", value = ConstraintMode.NO_CONSTRAINT ) )
|
||||||
public Person owner2;
|
public Person owner2;
|
||||||
|
|
||||||
@OneToOne
|
@OneToOne(fetch = FetchType.LAZY)
|
||||||
@JoinColumn( name = "OWNER_PERSON_ID3", foreignKey = @ForeignKey( name = "FK_CAR_OWNER3") )
|
@JoinColumn( name = "OWNER_PERSON_ID3", foreignKey = @ForeignKey( name = "FK_CAR_OWNER3") )
|
||||||
public Person owner3;
|
public Person owner3;
|
||||||
|
|
||||||
@OneToOne
|
@OneToOne(fetch = FetchType.LAZY)
|
||||||
@JoinColumn( name = "OWNER_PERSON_ID4", foreignKey = @ForeignKey( name = "FK_CAR_OWNER4", value = ConstraintMode.NO_CONSTRAINT ) )
|
@JoinColumn( name = "OWNER_PERSON_ID4", foreignKey = @ForeignKey( name = "FK_CAR_OWNER4", value = ConstraintMode.NO_CONSTRAINT ) )
|
||||||
public Person owner4;
|
public Person owner4;
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,98 @@
|
||||||
|
package org.hibernate.orm.test.loading;
|
||||||
|
|
||||||
|
import org.hibernate.testing.orm.junit.DomainModel;
|
||||||
|
import org.hibernate.testing.orm.junit.SessionFactory;
|
||||||
|
import org.hibernate.testing.orm.junit.SessionFactoryScope;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import jakarta.persistence.Entity;
|
||||||
|
import jakarta.persistence.Id;
|
||||||
|
import jakarta.persistence.OneToOne;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
|
@DomainModel(
|
||||||
|
annotatedClasses = {
|
||||||
|
LoadParentChildEntityTest.ContainingEntity.class,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
@SessionFactory
|
||||||
|
public class LoadParentChildEntityTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testLoad(SessionFactoryScope scope) {
|
||||||
|
scope.inTransaction(
|
||||||
|
session -> {
|
||||||
|
ContainingEntity parent = new ContainingEntity();
|
||||||
|
parent.setId( 1 );
|
||||||
|
|
||||||
|
ContainingEntity child = new ContainingEntity();
|
||||||
|
child.setId( 2 );
|
||||||
|
|
||||||
|
parent.setChild( child );
|
||||||
|
|
||||||
|
child.setParent( parent );
|
||||||
|
|
||||||
|
session.persist( parent );
|
||||||
|
session.persist( child );
|
||||||
|
|
||||||
|
assertThat( parent.getChild() ).isNotNull();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
scope.inTransaction(
|
||||||
|
session -> {
|
||||||
|
ContainingEntity load = session.load( ContainingEntity.class, 1 );
|
||||||
|
assertThat( load.getChild() ).isNotNull();
|
||||||
|
assertThat( load.getParent() ).isNull();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
scope.inTransaction(
|
||||||
|
session -> {
|
||||||
|
ContainingEntity load = session.load( ContainingEntity.class, 2 );
|
||||||
|
assertThat( load.getParent() ).isNotNull();
|
||||||
|
assertThat( load.getChild() ).isNull();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Entity(name = "containing")
|
||||||
|
public static class ContainingEntity {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
private Integer id;
|
||||||
|
|
||||||
|
@OneToOne
|
||||||
|
private ContainingEntity parent;
|
||||||
|
|
||||||
|
@OneToOne(mappedBy = "parent")
|
||||||
|
private ContainingEntity child;
|
||||||
|
|
||||||
|
public Integer getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(Integer id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ContainingEntity getParent() {
|
||||||
|
return parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setParent(ContainingEntity parent) {
|
||||||
|
this.parent = parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ContainingEntity getChild() {
|
||||||
|
return child;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setChild(ContainingEntity child) {
|
||||||
|
this.child = child;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -76,7 +76,6 @@ public class EntityWithBidirectionalOneToOneTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@FailureExpected( reason = "Change to attribute ordering triggered a problem with circularity detection", jiraKey = "HHH-14403" )
|
|
||||||
public void testGetMother(SessionFactoryScope scope) {
|
public void testGetMother(SessionFactoryScope scope) {
|
||||||
SQLStatementInspector statementInspector = (SQLStatementInspector) scope.getStatementInspector();
|
SQLStatementInspector statementInspector = (SQLStatementInspector) scope.getStatementInspector();
|
||||||
statementInspector.clear();
|
statementInspector.clear();
|
||||||
|
@ -167,8 +166,9 @@ public class EntityWithBidirectionalOneToOneTest {
|
||||||
assertSame( adoptedChild.getStepMother(), mother );
|
assertSame( adoptedChild.getStepMother(), mother );
|
||||||
assertSame( adoptedChild.getBiologicalMother(), mother );
|
assertSame( adoptedChild.getBiologicalMother(), mother );
|
||||||
|
|
||||||
statementInspector.assertExecutedCount( 1 );
|
statementInspector.assertExecutedCount( 2 );
|
||||||
statementInspector.assertNumberOfOccurrenceInQuery( 0, "join", 4 );
|
statementInspector.assertNumberOfOccurrenceInQuery( 0, "join", 4 );
|
||||||
|
statementInspector.assertNumberOfOccurrenceInQuery( 1, "join", 5 );
|
||||||
} );
|
} );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -230,7 +230,7 @@ public class EntityWithBidirectionalOneToOneTest {
|
||||||
|
|
||||||
statementInspector.assertExecutedCount( 2 );
|
statementInspector.assertExecutedCount( 2 );
|
||||||
statementInspector.assertNumberOfOccurrenceInQuery( 0, "join", 4);
|
statementInspector.assertNumberOfOccurrenceInQuery( 0, "join", 4);
|
||||||
statementInspector.assertNumberOfOccurrenceInQuery( 1, "join", 4);
|
statementInspector.assertNumberOfOccurrenceInQuery( 1, "join", 5);
|
||||||
} );
|
} );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -280,12 +280,60 @@ public class EntityWithBidirectionalOneToOneTest {
|
||||||
fetchablePath Child.mother.adopted.biologicalMother.adopted.stepMother --- Circular ---
|
fetchablePath Child.mother.adopted.biologicalMother.adopted.stepMother --- Circular ---
|
||||||
fetchablePath Child.mother.adopted.stepMother --- Circular --
|
fetchablePath Child.mother.adopted.stepMother --- Circular --
|
||||||
*/
|
*/
|
||||||
statementInspector.assertNumberOfOccurrenceInQuery( 0, "join", 4 );
|
statementInspector.assertNumberOfOccurrenceInQuery( 0, "join", 3 );
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetChild3(SessionFactoryScope scope) {
|
||||||
|
scope.inTransaction(
|
||||||
|
session -> {
|
||||||
|
Mother mother = new Mother( 10, "Strange mom" );
|
||||||
|
session.save( mother );
|
||||||
|
session.get( AdoptedChild.class, 3 ).setBiologicalMother( mother );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
SQLStatementInspector statementInspector = (SQLStatementInspector) scope.getStatementInspector();
|
||||||
|
statementInspector.clear();
|
||||||
|
scope.inTransaction( session -> {
|
||||||
|
final Child child = session.get( Child.class, 2 );
|
||||||
|
|
||||||
|
Mother mother = child.getMother();
|
||||||
|
assertTrue(
|
||||||
|
Hibernate.isInitialized( mother ),
|
||||||
|
"The mother eager OneToOne association is not initialized"
|
||||||
|
);
|
||||||
|
assertThat( mother, notNullValue() );
|
||||||
|
assertThat( mother.getName(), is( "Giulia" ) );
|
||||||
|
|
||||||
|
Child biologicalChild = mother.getBiologicalChild();
|
||||||
|
assertSame( biologicalChild, child );
|
||||||
|
assertTrue(
|
||||||
|
Hibernate.isInitialized( biologicalChild ),
|
||||||
|
"The child eager OneToOne association is not initialized"
|
||||||
|
);
|
||||||
|
|
||||||
|
AdoptedChild adoptedChild = mother.getAdopted();
|
||||||
|
assertThat( adoptedChild, notNullValue() );
|
||||||
|
assertTrue(
|
||||||
|
Hibernate.isInitialized( adoptedChild ),
|
||||||
|
"The adoptedChild eager OneToOne association is not initialized"
|
||||||
|
);
|
||||||
|
assertSame( adoptedChild.getStepMother(), mother );
|
||||||
|
assertThat( adoptedChild.getBiologicalMother(), notNullValue() );
|
||||||
|
assertTrue(
|
||||||
|
Hibernate.isInitialized( adoptedChild.getBiologicalMother() ),
|
||||||
|
"The biologicalMother eager OneToOne association is not initialized"
|
||||||
|
);
|
||||||
|
assertThat( adoptedChild.getBiologicalMother().getName(), is( "Strange mom" ) );
|
||||||
|
|
||||||
|
statementInspector.assertExecutedCount( 2 );
|
||||||
|
statementInspector.assertNumberOfOccurrenceInQuery( 0, "join", 3 );
|
||||||
|
statementInspector.assertNumberOfOccurrenceInQuery( 1, "join", 5 );
|
||||||
} );
|
} );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@FailureExpected( reason = "Change to attribute ordering triggered a problem with circularity detection", jiraKey = "HHH-14403" )
|
|
||||||
public void testGetAdoptedChild(SessionFactoryScope scope) {
|
public void testGetAdoptedChild(SessionFactoryScope scope) {
|
||||||
SQLStatementInspector statementInspector = (SQLStatementInspector) scope.getStatementInspector();
|
SQLStatementInspector statementInspector = (SQLStatementInspector) scope.getStatementInspector();
|
||||||
statementInspector.clear();
|
statementInspector.clear();
|
||||||
|
@ -315,7 +363,7 @@ public class EntityWithBidirectionalOneToOneTest {
|
||||||
);
|
);
|
||||||
assertThat( adoptedChild.getBiologicalMother(), nullValue() );
|
assertThat( adoptedChild.getBiologicalMother(), nullValue() );
|
||||||
|
|
||||||
statementInspector.assertExecutedCount( 2 );
|
statementInspector.assertExecutedCount( 1 );
|
||||||
/*
|
/*
|
||||||
fetchablePath: AdoptedChild.biologicalMother --- NO circular ---
|
fetchablePath: AdoptedChild.biologicalMother --- NO circular ---
|
||||||
fetchablePath: AdoptedChild.biologicalMother.biologicalChild --- NO circular ---
|
fetchablePath: AdoptedChild.biologicalMother.biologicalChild --- NO circular ---
|
||||||
|
@ -334,8 +382,7 @@ public class EntityWithBidirectionalOneToOneTest {
|
||||||
fetchablePath: AdoptedChild.stepMother.biologicalChild.mother --- Circular ---
|
fetchablePath: AdoptedChild.stepMother.biologicalChild.mother --- Circular ---
|
||||||
fetchablePath: AdoptedChild.stepMother.adopted --- Circular ---
|
fetchablePath: AdoptedChild.stepMother.adopted --- Circular ---
|
||||||
*/
|
*/
|
||||||
statementInspector.assertNumberOfOccurrenceInQuery( 0, "join", 3 );
|
statementInspector.assertNumberOfOccurrenceInQuery( 0, "join", 5 );
|
||||||
statementInspector.assertNumberOfOccurrenceInQuery( 1, "join", 4 );
|
|
||||||
} );
|
} );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -401,14 +448,14 @@ public class EntityWithBidirectionalOneToOneTest {
|
||||||
|
|
||||||
assertThat( biologicalMother.getAdopted(), nullValue() );
|
assertThat( biologicalMother.getAdopted(), nullValue() );
|
||||||
|
|
||||||
statementInspector.assertExecutedCount( 2 );
|
statementInspector.assertExecutedCount( 3 );
|
||||||
statementInspector.assertNumberOfOccurrenceInQuery( 0, "join", 4 );
|
statementInspector.assertNumberOfOccurrenceInQuery( 0, "join", 3 );
|
||||||
statementInspector.assertNumberOfOccurrenceInQuery( 1, "join", 4 );
|
statementInspector.assertNumberOfOccurrenceInQuery( 1, "join", 5 );
|
||||||
|
statementInspector.assertNumberOfOccurrenceInQuery( 2, "join", 3 );
|
||||||
} );
|
} );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@FailureExpected( reason = "Change to attribute ordering triggered a problem with circularity detection", jiraKey = "HHH-14403" )
|
|
||||||
public void testHqlSelectMother(SessionFactoryScope scope) {
|
public void testHqlSelectMother(SessionFactoryScope scope) {
|
||||||
SQLStatementInspector statementInspector = (SQLStatementInspector) scope.getStatementInspector();
|
SQLStatementInspector statementInspector = (SQLStatementInspector) scope.getStatementInspector();
|
||||||
statementInspector.clear();
|
statementInspector.clear();
|
||||||
|
@ -424,12 +471,10 @@ public class EntityWithBidirectionalOneToOneTest {
|
||||||
Child child = mother.getBiologicalChild();
|
Child child = mother.getBiologicalChild();
|
||||||
assertThat( child, notNullValue() );
|
assertThat( child, notNullValue() );
|
||||||
assertThat( child.getName(), is( "Luis" ) );
|
assertThat( child.getName(), is( "Luis" ) );
|
||||||
statementInspector.assertExecutedCount( 3 );
|
statementInspector.assertExecutedCount( 2 );
|
||||||
statementInspector.assertNumberOfOccurrenceInQuery( 0, "join", 1 );
|
statementInspector.assertNumberOfOccurrenceInQuery( 0, "join", 1 );
|
||||||
// Mother.biologicalChild
|
// Mother.biologicalChild
|
||||||
statementInspector.assertNumberOfOccurrenceInQuery( 1, "join", 4 );
|
statementInspector.assertNumberOfOccurrenceInQuery( 1, "join", 5 );
|
||||||
// Mother.adopted
|
|
||||||
statementInspector.assertNumberOfOccurrenceInQuery( 2, "join", 3 );
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue