Fix loading OnetoOne self referencing entity

This commit is contained in:
Andrea Boriero 2021-11-18 14:55:14 +01:00 committed by Andrea Boriero
parent aded53a760
commit d21db9e807
9 changed files with 279 additions and 86 deletions

View File

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

View File

@ -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) {

View File

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

View File

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

View File

@ -175,7 +175,8 @@ public class DomainResultCreationStateImpl
} }
@Override @Override
public void registerVisitedAssociationKey(AssociationKey associationKey) { public boolean registerVisitedAssociationKey(AssociationKey associationKey) {
return false;
} }
@Override @Override

View File

@ -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){

View File

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

View File

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

View File

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