diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/SimpleForeignKeyDescriptor.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/SimpleForeignKeyDescriptor.java index b12f0c2c84..eb8227a2d5 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/SimpleForeignKeyDescriptor.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/SimpleForeignKeyDescriptor.java @@ -25,6 +25,7 @@ import org.hibernate.sql.ast.spi.SqlSelection; import org.hibernate.sql.ast.tree.expression.ColumnReference; import org.hibernate.sql.ast.tree.from.TableGroup; import org.hibernate.sql.ast.tree.from.TableReference; +import org.hibernate.sql.ast.tree.from.TableReferenceJoin; import org.hibernate.sql.ast.tree.predicate.ComparisonPredicate; import org.hibernate.sql.ast.tree.predicate.Predicate; import org.hibernate.sql.results.internal.domain.basic.BasicResult; @@ -63,14 +64,16 @@ public class SimpleForeignKeyDescriptor implements ForeignKeyDescriptor { DomainResultCreationState creationState) { final SqlAstCreationState sqlAstCreationState = creationState.getSqlAstCreationState(); final SqlExpressionResolver sqlExpressionResolver = sqlAstCreationState.getSqlExpressionResolver(); + final TableReference keyTableKeyReference = getKeyTableReference( tableGroup, tableGroup ); + final SqlSelection sqlSelection = sqlExpressionResolver.resolveSqlSelection( sqlExpressionResolver.resolveSqlExpression( SqlExpressionResolver.createColumnReferenceKey( - tableGroup.getPrimaryTableReference(), + keyTableKeyReference, keyColumnExpression ), s -> new ColumnReference( - tableGroup.getPrimaryTableReference().getIdentificationVariable(), + keyTableKeyReference, keyColumnExpression, jdbcMapping, creationState.getSqlAstCreationState().getCreationContext().getSessionFactory() @@ -95,25 +98,27 @@ public class SimpleForeignKeyDescriptor implements ForeignKeyDescriptor { JoinType joinType, SqlExpressionResolver sqlExpressionResolver, SqlAstCreationContext creationContext) { - final TableReference tableReference = lhs.resolveTableReference( targetColumnContainingTable ); + final TableReference targetTableReference = lhs.resolveTableReference( targetColumnContainingTable ); final ColumnReference targetReference = (ColumnReference) sqlExpressionResolver.resolveSqlExpression( - SqlExpressionResolver.createColumnReferenceKey( tableReference, keyColumnExpression ), + SqlExpressionResolver.createColumnReferenceKey( targetTableReference, keyColumnExpression ), s -> new ColumnReference( - tableReference.getIdentificationVariable(), + targetTableReference.getIdentificationVariable(), targetColumnExpression, jdbcMapping, creationContext.getSessionFactory() ) ); + final TableReference keyTableKeyReference = getKeyTableReference( lhs, tableGroup ); + final ColumnReference keyReference = (ColumnReference) sqlExpressionResolver.resolveSqlExpression( SqlExpressionResolver.createColumnReferenceKey( - tableGroup.getPrimaryTableReference(), + keyTableKeyReference, keyColumnExpression ), s -> new ColumnReference( - tableGroup.getPrimaryTableReference().getIdentificationVariable(), + keyTableKeyReference.getIdentificationVariable(), keyColumnExpression, jdbcMapping, creationContext.getSessionFactory() @@ -127,6 +132,15 @@ public class SimpleForeignKeyDescriptor implements ForeignKeyDescriptor { ); } + protected TableReference getKeyTableReference(TableGroup lhs, TableGroup tableGroup) { + for ( TableReferenceJoin tableJoin : lhs.getTableReferenceJoins() ) { + if ( tableJoin.getJoinedTableReference().getTableExpression().equals( keyColumnContainingTable ) ) { + return tableJoin.getJoinedTableReference(); + } + } + return tableGroup.getPrimaryTableReference(); + } + @Override public JavaTypeDescriptor getJavaTypeDescriptor() { return jdbcMapping.getJavaTypeDescriptor(); @@ -144,7 +158,13 @@ public class SimpleForeignKeyDescriptor implements ForeignKeyDescriptor { @Override public void visitColumnMappings(FkColumnMappingConsumer consumer) { - consumer.consume( keyColumnContainingTable, keyColumnExpression, targetColumnContainingTable, targetColumnExpression, jdbcMapping ); + consumer.consume( + keyColumnContainingTable, + keyColumnExpression, + targetColumnContainingTable, + targetColumnExpression, + jdbcMapping + ); } @Override diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/sql/exec/manytoone/EntityWithManyToOneJoinTableTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/sql/exec/manytoone/EntityWithManyToOneJoinTableTest.java index 7b14ee3b65..1dd7f0ee7a 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/sql/exec/manytoone/EntityWithManyToOneJoinTableTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/sql/exec/manytoone/EntityWithManyToOneJoinTableTest.java @@ -10,10 +10,10 @@ import java.util.Calendar; import org.hibernate.stat.spi.StatisticsImplementor; +import org.hibernate.testing.orm.domain.gambit.BasicEntity; import org.hibernate.testing.orm.domain.gambit.EntityWithManyToOneJoinTable; import org.hibernate.testing.orm.domain.gambit.SimpleEntity; import org.hibernate.testing.orm.junit.DomainModel; -import org.hibernate.testing.orm.junit.FailureExpected; import org.hibernate.testing.orm.junit.ServiceRegistry; import org.hibernate.testing.orm.junit.SessionFactory; import org.hibernate.testing.orm.junit.SessionFactoryScope; @@ -32,7 +32,8 @@ import static org.hamcrest.MatcherAssert.assertThat; @DomainModel( annotatedClasses = { EntityWithManyToOneJoinTable.class, - SimpleEntity.class + SimpleEntity.class, + BasicEntity.class } ) @ServiceRegistry @@ -75,7 +76,6 @@ public class EntityWithManyToOneJoinTableTest { } @Test - @FailureExpected public void testSaveInDifferentTransactions(SessionFactoryScope scope) { EntityWithManyToOneJoinTable entity = new EntityWithManyToOneJoinTable( 3, "second", Integer.MAX_VALUE ); @@ -83,7 +83,7 @@ public class EntityWithManyToOneJoinTableTest { 4, Calendar.getInstance().getTime(), Calendar.getInstance().toInstant(), - Integer.MAX_VALUE -1 , + Integer.MAX_VALUE - 1, Long.MAX_VALUE, null ); @@ -110,22 +110,25 @@ public class EntityWithManyToOneJoinTableTest { } @Test - @FailureExpected public void testHqlSelect(SessionFactoryScope scope) { final StatisticsImplementor statistics = scope.getSessionFactory().getStatistics(); statistics.clear(); scope.inTransaction( session -> { final EntityWithManyToOneJoinTable result = session.createQuery( - "select e from EntityWithManyToOneJoinTable e where e.id = 2", + "select e from EntityWithManyToOneJoinTable e where e.id = 1", EntityWithManyToOneJoinTable.class ).uniqueResult(); assertThat( result, notNullValue() ); - assertThat( result.getId(), is( 2 ) ); + assertThat( result.getId(), is( 1 ) ); assertThat( result.getName(), is( "first" ) ); - assertThat( statistics.getPrepareStatementCount(), is( 1L ) ); + assertThat( statistics.getPrepareStatementCount(), is( 2L ) ); + + assertThat( result.getOther().getSomeInteger(), is( Integer.MAX_VALUE ) ); + + assertThat( statistics.getPrepareStatementCount(), is( 2L ) ); } ); } @@ -140,6 +143,7 @@ public class EntityWithManyToOneJoinTableTest { "select e.name from EntityWithManyToOneJoinTable e where e.other.id = 2", String.class ).uniqueResult(); + assertThat( value, equalTo( "first" ) ); assertThat( statistics.getPrepareStatementCount(), is( 1L ) ); @@ -148,29 +152,63 @@ public class EntityWithManyToOneJoinTableTest { } @Test - @FailureExpected public void testHqlSelectWithJoin(SessionFactoryScope scope) { + final StatisticsImplementor statistics = scope.getSessionFactory().getStatistics(); + statistics.clear(); scope.inTransaction( session -> { - final String value = session.createQuery( - "select from EntityWithManyToOneJoinTable e where e.id = 2", - String.class + final EntityWithManyToOneJoinTable result = session.createQuery( + "select e from EntityWithManyToOneJoinTable e join e.other where e.id = 1", + EntityWithManyToOneJoinTable.class ).uniqueResult(); - assertThat( value, equalTo( "first" ) ); + assertThat( result, notNullValue() ); + assertThat( result.getId(), is( 1 ) ); + assertThat( result.getName(), is( "first" ) ); + + assertThat( statistics.getPrepareStatementCount(), is( 2L ) ); + + assertThat( result.getOther().getId(), is( 2 ) ); + assertThat( result.getOther().getSomeInteger(), is( Integer.MAX_VALUE ) ); + + assertThat( statistics.getPrepareStatementCount(), is( 2L ) ); + } + ); + } + + @Test + public void testHqlSelectWithJoinFetch(SessionFactoryScope scope) { + final StatisticsImplementor statistics = scope.getSessionFactory().getStatistics(); + statistics.clear(); + scope.inTransaction( + session -> { + final EntityWithManyToOneJoinTable result = session.createQuery( + "select e from EntityWithManyToOneJoinTable e join fetch e.other where e.id = 1", + EntityWithManyToOneJoinTable.class + ).uniqueResult(); + + assertThat( result, notNullValue() ); + assertThat( result.getId(), is( 1 ) ); + assertThat( result.getName(), is( "first" ) ); + + assertThat( statistics.getPrepareStatementCount(), is( 1L ) ); + + assertThat( result.getOther().getId(), is( 2 ) ); + assertThat( result.getOther().getSomeInteger(), is( Integer.MAX_VALUE ) ); + + assertThat( statistics.getPrepareStatementCount(), is( 1L ) ); } ); } @Test - @FailureExpected public void testUpdate(SessionFactoryScope scope) { - EntityWithManyToOneJoinTable entity = new EntityWithManyToOneJoinTable( 1, "first", Integer.MAX_VALUE ); + EntityWithManyToOneJoinTable entity = new EntityWithManyToOneJoinTable( 2, "second", Integer.MAX_VALUE ); SimpleEntity other = new SimpleEntity( - 2, + 4, Calendar.getInstance().getTime(), null, - Integer.MAX_VALUE, + 100, Long.MAX_VALUE, null ); @@ -183,17 +221,17 @@ public class EntityWithManyToOneJoinTableTest { } ); SimpleEntity anOther = new SimpleEntity( - 3, + 5, Calendar.getInstance().getTime(), null, - Integer.MIN_VALUE, + Integer.MIN_VALUE + 5, Long.MIN_VALUE, null ); scope.inTransaction( session -> { - final EntityWithManyToOneJoinTable loaded = session.get( EntityWithManyToOneJoinTable.class, 1 ); + final EntityWithManyToOneJoinTable loaded = session.get( EntityWithManyToOneJoinTable.class, 2 ); assert loaded != null; session.save( anOther ); loaded.setOther( anOther ); @@ -202,10 +240,10 @@ public class EntityWithManyToOneJoinTableTest { scope.inTransaction( session -> { - final EntityWithManyToOneJoinTable loaded = session.get( EntityWithManyToOneJoinTable.class, 1 ); + final EntityWithManyToOneJoinTable loaded = session.get( EntityWithManyToOneJoinTable.class, 2 ); assertThat( loaded.getOther(), notNullValue() ); - assertThat( loaded.getOther().getId(), equalTo( 3 ) ); + assertThat( loaded.getOther().getId(), equalTo( 5 ) ); } ); } diff --git a/hibernate-testing/src/main/java/org/hibernate/testing/orm/domain/gambit/EntityWithManyToOneJoinTable.java b/hibernate-testing/src/main/java/org/hibernate/testing/orm/domain/gambit/EntityWithManyToOneJoinTable.java index da6f4f7a9f..a64ab6b411 100644 --- a/hibernate-testing/src/main/java/org/hibernate/testing/orm/domain/gambit/EntityWithManyToOneJoinTable.java +++ b/hibernate-testing/src/main/java/org/hibernate/testing/orm/domain/gambit/EntityWithManyToOneJoinTable.java @@ -7,6 +7,7 @@ package org.hibernate.testing.orm.domain.gambit; import javax.persistence.Entity; +import javax.persistence.FetchType; import javax.persistence.Id; import javax.persistence.JoinTable; import javax.persistence.ManyToOne; @@ -22,6 +23,7 @@ public class EntityWithManyToOneJoinTable { private String name; private SimpleEntity other; private Integer someInteger; + private BasicEntity lazyOther; public EntityWithManyToOneJoinTable() { } @@ -59,6 +61,16 @@ public class EntityWithManyToOneJoinTable { this.other = other; } + @ManyToOne(fetch = FetchType.LAZY) + @JoinTable(name = "ENTITY_ANOTHER") + public BasicEntity getLazyOther() { + return lazyOther; + } + + public void setLazyOther(BasicEntity lazyOther) { + this.lazyOther = lazyOther; + } + public Integer getSomeInteger() { return someInteger; }