diff --git a/hibernate-core/src/main/java/org/hibernate/generator/values/internal/GeneratedValuesMappingProducer.java b/hibernate-core/src/main/java/org/hibernate/generator/values/internal/GeneratedValuesMappingProducer.java index f14998ad1248..177c834f1fdb 100644 --- a/hibernate-core/src/main/java/org/hibernate/generator/values/internal/GeneratedValuesMappingProducer.java +++ b/hibernate-core/src/main/java/org/hibernate/generator/values/internal/GeneratedValuesMappingProducer.java @@ -49,6 +49,7 @@ public JdbcValuesMapping resolve( null, sqlSelections::add, loadQueryInfluencers, + false, sessionFactory ); diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/ToOneAttributeMapping.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/ToOneAttributeMapping.java index fe964e02f7cc..f62c7577e973 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/ToOneAttributeMapping.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/ToOneAttributeMapping.java @@ -1543,8 +1543,8 @@ public static class EntityB { else { side = this.sideNature; } - - if ( ( fetchTiming == FetchTiming.IMMEDIATE && selected ) || needsJoinFetch( side ) ) { + if ( fetchTiming == FetchTiming.IMMEDIATE && selected + || !creationState.getSqlAstCreationState().isProcedureOrNativeQuery() && needsJoinFetch( side ) ) { final TableGroup tableGroup = determineTableGroupForFetch( fetchablePath, fetchParent, @@ -1675,9 +1675,12 @@ else if ( hasNotFoundAction() private boolean needsJoinFetch(ForeignKeyDescriptor.Nature side) { if ( side == ForeignKeyDescriptor.Nature.TARGET ) { - // The target model part doesn't correspond to the identifier of the target entity mapping - // so we must eagerly fetch with a join (subselect would still cause problems). + // With composite identifier if the target model part doesn't correspond to the identifier of the target entity mapping + // we must eagerly fetch with a join (subselect would still cause problems). final EntityIdentifierMapping identifier = entityMappingType.getIdentifierMapping(); + if ( identifier instanceof BasicEntityIdentifierMappingImpl ) { + return false; + } final ValuedModelPart targetPart = foreignKeyDescriptor.getTargetPart(); if ( identifier != targetPart ) { // If the identifier and the target part of the same class, we can preserve laziness as deferred loading will still work diff --git a/hibernate-core/src/main/java/org/hibernate/query/results/internal/DomainResultCreationStateImpl.java b/hibernate-core/src/main/java/org/hibernate/query/results/internal/DomainResultCreationStateImpl.java index e7b75c363582..cd2ed1d223f6 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/results/internal/DomainResultCreationStateImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/query/results/internal/DomainResultCreationStateImpl.java @@ -82,6 +82,7 @@ public class DomainResultCreationStateImpl private boolean processingKeyFetches = false; private boolean resolvingCircularFetch; private ForeignKeyDescriptor.Nature currentlyResolvingForeignKeySide; + private boolean isProcedureOrNativeQuery; public DomainResultCreationStateImpl( String stateIdentifier, @@ -89,6 +90,7 @@ public DomainResultCreationStateImpl( Map> legacyFetchBuilders, Consumer sqlSelectionConsumer, LoadQueryInfluencers loadQueryInfluencers, + boolean isProcedureOrNativeQuery, SessionFactoryImplementor sessionFactory) { this.stateIdentifier = stateIdentifier; this.jdbcResultsMetadata = jdbcResultsMetadata; @@ -100,6 +102,8 @@ public DomainResultCreationStateImpl( this.legacyFetchResolver = new LegacyFetchResolver( legacyFetchBuilders ); this.sessionFactory = sessionFactory; + + this.isProcedureOrNativeQuery = isProcedureOrNativeQuery; } public SessionFactoryImplementor getSessionFactory() { @@ -350,11 +354,8 @@ public Fetch visitIdentifierFetch(EntityResultGraphNode fetchParent) { final EntityIdentifierMapping identifierMapping = parentModelPart.getEntityMappingType().getIdentifierMapping(); final String identifierAttributeName = attributeName( identifierMapping ); - //noinspection unchecked - final FetchBuilder explicitFetchBuilder = (FetchBuilder) fetchBuilderResolverStack - .getCurrent() - .apply( identifierMapping ); - LegacyFetchBuilder fetchBuilderLegacy; + final FetchBuilder explicitFetchBuilder = fetchBuilderResolverStack.getCurrent().apply( identifierMapping ); + final LegacyFetchBuilder fetchBuilderLegacy; if ( explicitFetchBuilder == null ) { fetchBuilderLegacy = legacyFetchResolver.resolve( fromClauseAccess.findTableGroup( fetchParent.getNavigablePath() ) @@ -414,9 +415,7 @@ private Consumer createFetchableConsumer(FetchParent fetchParent, Imm if ( !fetchable.isSelectable() ) { return; } - FetchBuilder explicitFetchBuilder = (FetchBuilder) fetchBuilderResolverStack - .getCurrent() - .apply( fetchable ); + FetchBuilder explicitFetchBuilder = fetchBuilderResolverStack.getCurrent().apply( fetchable ); LegacyFetchBuilder fetchBuilderLegacy; if ( explicitFetchBuilder == null ) { fetchBuilderLegacy = legacyFetchResolver.resolve( @@ -490,4 +489,8 @@ public void setCurrentlyResolvingForeignKeyPart(ForeignKeyDescriptor.Nature curr this.currentlyResolvingForeignKeySide = currentlyResolvingForeignKeySide; } + @Override + public boolean isProcedureOrNativeQuery() { + return isProcedureOrNativeQuery; + } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/results/internal/ResultSetMappingImpl.java b/hibernate-core/src/main/java/org/hibernate/query/results/internal/ResultSetMappingImpl.java index e8e646fcc506..98aff703491b 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/results/internal/ResultSetMappingImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/query/results/internal/ResultSetMappingImpl.java @@ -199,6 +199,7 @@ public JdbcValuesMapping resolve( legacyFetchBuilders, sqlSelections::add, loadQueryInfluencers, + true, sessionFactory ); diff --git a/hibernate-core/src/main/java/org/hibernate/sql/ast/spi/SqlAstCreationState.java b/hibernate-core/src/main/java/org/hibernate/sql/ast/spi/SqlAstCreationState.java index 27db4fc83030..8fc2102417f6 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/ast/spi/SqlAstCreationState.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/ast/spi/SqlAstCreationState.java @@ -57,4 +57,8 @@ default boolean supportsEntityNameUsage() { @Internal default void applyOrdering(TableGroup tableGroup, OrderByFragment orderByFragment) { } + + default boolean isProcedureOrNativeQuery(){ + return false; + } } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/query/NativeQueryJoinTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/query/NativeQueryJoinTest.java new file mode 100644 index 000000000000..da6503a2c3df --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/query/NativeQueryJoinTest.java @@ -0,0 +1,166 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.orm.test.jpa.query; + +import jakarta.persistence.CascadeType; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.OneToOne; +import jakarta.persistence.Table; +import org.hibernate.testing.orm.junit.DomainModel; +import org.hibernate.testing.orm.junit.JiraKey; +import org.hibernate.testing.orm.junit.SessionFactory; +import org.hibernate.testing.orm.junit.SessionFactoryScope; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.math.BigDecimal; +import java.util.List; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; + +@DomainModel( + annotatedClasses = { + NativeQueryJoinTest.Order.class, + NativeQueryJoinTest.OrderInfo.class, + } +) +@SessionFactory +@JiraKey("HHH-19524") +public class NativeQueryJoinTest { + + private static final long ORDER_ID = 1L; + private static final long ORDER_INFO_ID = 2L; + private static final String ORDER_INFO_DESCRIPTION = "first order"; + + @BeforeEach + public void setup(SessionFactoryScope scope) { + scope.inTransaction( + session -> { + OrderInfo additionalInfo = new OrderInfo( + new BigDecimal( ORDER_INFO_ID ), + ORDER_INFO_DESCRIPTION + ); + Order order = new Order( ORDER_ID, 1L, additionalInfo ); + session.persist( order ); + } + ); + } + + @AfterEach + public void teardown(SessionFactoryScope scope) { + scope.getSessionFactory().getSchemaManager().truncateMappedObjects(); + } + + @Test + public void testFind(SessionFactoryScope scope) { + scope.inTransaction( + session -> { + Order order = session.find( Order.class, ORDER_ID ); + OrderInfo additionalInfo = order.getOrderInfo(); + assertThat( additionalInfo.getDescription() ).isEqualTo( ORDER_INFO_DESCRIPTION ); + } ); + } + + @Test + public void testQuery(SessionFactoryScope scope) { + scope.inTransaction( + session -> { + List ids = session.createQuery("select o.orderId from Order o", Long.class ).list(); + session.createMutationQuery( "update Order set description = :des" ).setParameter( "des", "abc" ).executeUpdate(); + } ); + } + + @Test + public void testNativeQuery(SessionFactoryScope scope) { + scope.inTransaction( + session -> { + String query = "select o.* from ORDER_TABLE o where o.ORDER_ID = ?1"; + List orders = session.createNativeQuery( query, Order.class ) + .setParameter( 1, ORDER_ID ) + .list(); + Order order = orders.get( 0 ); + OrderInfo additionalInfo = order.getOrderInfo(); + assertThat( additionalInfo.getDescription() ).isEqualTo( ORDER_INFO_DESCRIPTION ); + } ); + } + + @Table(name = "ORDER_TABLE") + @Entity(name = "Order") + public static class Order { + + @Id + @Column(name = "ORDER_ID") + private Long orderId; + + private long orderNumber; + + private String description; + + @OneToOne(mappedBy = "order", fetch = FetchType.LAZY, cascade = CascadeType.PERSIST) + private OrderInfo orderInfo; + + public Order() { + } + + public Long getOrderId() { + return orderId; + } + + public long getOrderNumber() { + return orderNumber; + } + + public OrderInfo getOrderInfo() { + return orderInfo; + } + + public Order(Long orderId, long orderNumber, OrderInfo additionalInfo) { + this.orderId = orderId; + this.orderNumber = orderNumber; + this.orderInfo = additionalInfo; + additionalInfo.order = this; + } + } + + @Entity(name = "OrderInfo") + @Table(name = "ORDER_INFO_TABLE") + public static class OrderInfo { + + @Id + @Column(name = "ORDER_INFO_ID") + private BigDecimal orderInfoId; + + private String description; + + @OneToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "ORDER_ID") + private Order order; + + public OrderInfo() { + } + + public OrderInfo(BigDecimal orderInfoId, String description) { + this.orderInfoId = orderInfoId; + this.description = description; + } + + public BigDecimal getOrderInfoId() { + return orderInfoId; + } + + public String getDescription() { + return description; + } + + public Order getOrder() { + return order; + } + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/onetoone/embeddedid/OneToOneEmbeddedIdTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/onetoone/embeddedid/OneToOneEmbeddedIdTest.java new file mode 100644 index 000000000000..c1cf3c9e32ba --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/onetoone/embeddedid/OneToOneEmbeddedIdTest.java @@ -0,0 +1,247 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.orm.test.onetoone.embeddedid; + +import jakarta.persistence.Column; +import jakarta.persistence.Embeddable; +import jakarta.persistence.EmbeddedId; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.OneToOne; +import jakarta.persistence.Table; +import org.hibernate.testing.bytecode.enhancement.extension.BytecodeEnhanced; +import org.hibernate.testing.orm.junit.DomainModel; +import org.hibernate.testing.orm.junit.JiraKey; +import org.hibernate.testing.orm.junit.SessionFactory; +import org.hibernate.testing.orm.junit.SessionFactoryScope; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.util.List; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; + +@DomainModel( + annotatedClasses = { + OneToOneEmbeddedIdTest.EntityA.class, + OneToOneEmbeddedIdTest.EntityB.class, + } +) +@SessionFactory +@BytecodeEnhanced(runNotEnhancedAsWell = true) +@JiraKey("HHH-17838") +public class OneToOneEmbeddedIdTest { + + private static final String ENTITY_A_NAME = "a"; + private static final String ENTITY_B_NAME = "B"; + + private static final Integer ENTITY_A_ID1 = 1; + private static final String ENTITY_A_ID2 = "1"; + + private static final Integer ENTITY_B_ID1 = 2; + private static final String ENTITY_B_ID2 = "2"; + + @BeforeEach + public void setUp(SessionFactoryScope scope) { + scope.inTransaction( + session -> { + EntityAKey entityAKey = new EntityAKey( ENTITY_A_ID1, ENTITY_A_ID2 ); + EntityA entityA = new EntityA( entityAKey, ENTITY_A_NAME ); + + EntityBKey entityBKey = new EntityBKey( ENTITY_B_ID1, ENTITY_B_ID2 ); + EntityB entityB = new EntityB( entityBKey, entityA, ENTITY_B_NAME ); + + session.persist( entityA ); + session.persist( entityB ); + } + ); + } + + @AfterEach + public void tearDown(SessionFactoryScope scope) { + scope.getSessionFactory().getSchemaManager().truncateMappedObjects(); + } + + @Test + public void testFind(SessionFactoryScope scope) { + scope.inTransaction( + session -> { + EntityAKey entityAKey = new EntityAKey( ENTITY_A_ID1, ENTITY_A_ID2 ); + EntityA entityA = session.find( EntityA.class, entityAKey ); + assertThat( entityA ).isNotNull(); + assertThat( entityA.getName() ).isEqualTo( ENTITY_A_NAME ); + + EntityB entityB = entityA.getEntityB(); + assertThat( entityB ).isNotNull(); + + EntityBKey key = entityB.getEntityBKey(); + assertThat( key.id1 ).isEqualTo( ENTITY_B_ID1 ); + assertThat( key.id2 ).isEqualTo( ENTITY_B_ID2 ); + + assertThat( entityB.getName() ).isEqualTo( ENTITY_B_NAME ); + } + ); + } + + @Test + public void testFind2(SessionFactoryScope scope) { + scope.inTransaction( + session -> { + EntityBKey entityBKey = new EntityBKey( ENTITY_B_ID1, ENTITY_B_ID2 ); + EntityB entityB = session.find( EntityB.class, entityBKey ); + assertThat( entityB ).isNotNull(); + assertThat( entityB.getName() ).isEqualTo( ENTITY_B_NAME ); + + EntityA entityA = entityB.getEntityA(); + assertThat( entityA ).isNotNull(); + + EntityAKey entityAKey = entityA.getEntityAKey(); + assertThat( entityAKey.id1 ).isEqualTo( ENTITY_A_ID1 ); + assertThat( entityAKey.id2 ).isEqualTo( ENTITY_A_ID2 ); + + assertThat( entityA.getName() ).isEqualTo( ENTITY_A_NAME ); + } + ); + } + + @Test + public void testNativeQuery(SessionFactoryScope scope) { + scope.inTransaction( + session -> { + String query = "select a.* from ENTITY_A a"; + List entityAS = session.createNativeQuery( query, EntityA.class ).list(); + assertThat( entityAS.size() ).isEqualTo( 1 ); + EntityA entityA = entityAS.get( 0 ); + assertThat( entityA.getName() ).isEqualTo( ENTITY_A_NAME ); + assertThat( entityA.getEntityB().getName() ).isEqualTo( ENTITY_B_NAME ); + } + ); + } + + @Test + public void testNativeQuery2(SessionFactoryScope scope) { + scope.inTransaction( + session -> { + String query = "select b.* from ENTITY_B b"; + List entityBS = session.createNativeQuery( query, EntityB.class ).list(); + assertThat( entityBS.size() ).isEqualTo( 1 ); + + EntityB entityB = entityBS.get( 0 ); + assertThat( entityB.getName()).isEqualTo( ENTITY_B_NAME ); + assertThat( entityB.getEntityA().getName()).isEqualTo( ENTITY_A_NAME ); + } + ); + } + + @Entity(name = "EntityA") + @Table(name= "ENTITY_A") + public static class EntityA { + + @EmbeddedId + private EntityAKey entityAKey; + + private String name; + + @OneToOne(mappedBy = "entityA", fetch = FetchType.LAZY) + private EntityB entityB; + + public EntityA() { + } + + public EntityA(EntityAKey key, String name) { + this.entityAKey = key; + this.name = name; + } + + public EntityAKey getEntityAKey() { + return entityAKey; + } + + public String getName() { + return name; + } + + public EntityB getEntityB() { + return entityB; + } + } + + @Embeddable + public static class EntityAKey { + + @Column(name = "id1") + private Integer id1; + + @Column(name = "id2") + private String id2; + + public EntityAKey() { + } + + public EntityAKey(Integer id1, String id2) { + this.id1 = id1; + this.id2 = id2; + } + } + + @Entity(name = "EntityB") + @Table(name = "ENTITY_B") + public static class EntityB { + @EmbeddedId + private EntityBKey entityBKey; + + private String name; + + @OneToOne(optional = false, fetch = FetchType.LAZY) +// @JoinColumns({ +// @JoinColumn(name = "id1", referencedColumnName = "id1", nullable = false, +// insertable = false, updatable = false), +// @JoinColumn(name = "id2", referencedColumnName = "id2", nullable = false, +// insertable = false, updatable = false) +// }) + private EntityA entityA; + + public EntityB() { + } + + public EntityB(EntityBKey key, EntityA testEntity, String name) { + this.entityBKey = key; + this.entityA = testEntity; + testEntity.entityB = this; + this.name = name; + } + + public EntityBKey getEntityBKey() { + return entityBKey; + } + + public EntityA getEntityA() { + return entityA; + } + + public String getName() { + return name; + } + } + + @Embeddable + public static class EntityBKey { + + @Column(name = "id1") + private Integer id1; + + @Column(name = "id2") + private String id2; + + public EntityBKey() { + } + + public EntityBKey(Integer documentType, String no) { + this.id1 = documentType; + this.id2 = no; + } + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/onetoone/embeddedid/OneToOneJoinColumnsEmbeddedIdTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/onetoone/embeddedid/OneToOneJoinColumnsEmbeddedIdTest.java index 53a08d46373b..3161ddc77ea6 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/onetoone/embeddedid/OneToOneJoinColumnsEmbeddedIdTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/onetoone/embeddedid/OneToOneJoinColumnsEmbeddedIdTest.java @@ -12,6 +12,7 @@ import jakarta.persistence.JoinColumn; import jakarta.persistence.JoinColumns; import jakarta.persistence.OneToOne; +import jakarta.persistence.Table; import org.hibernate.testing.bytecode.enhancement.extension.BytecodeEnhanced; import org.hibernate.testing.orm.junit.DomainModel; import org.hibernate.testing.orm.junit.JiraKey; @@ -21,6 +22,8 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import java.util.List; + import static org.assertj.core.api.AssertionsForClassTypes.assertThat; @DomainModel( @@ -34,15 +37,24 @@ @JiraKey("HHH-17838") public class OneToOneJoinColumnsEmbeddedIdTest { + private static final String ENTITY_A_NAME = "a"; + private static final String ENTITY_B_NAME = "B"; + + private static final Integer ENTITY_A_ID1 = 1; + private static final String ENTITY_A_ID2 = "1"; + + private static final Integer ENTITY_B_ID1 = 1; + private static final String ENTITY_B_ID2 = "1"; + @BeforeEach public void setUp(SessionFactoryScope scope) { scope.inTransaction( session -> { - EntityAKey entityAKey = new EntityAKey( 1, "1" ); - EntityA entityA = new EntityA( entityAKey, "te1" ); + EntityAKey entityAKey = new EntityAKey( ENTITY_A_ID1, ENTITY_A_ID2 ); + EntityA entityA = new EntityA( entityAKey, ENTITY_A_NAME ); - EntityBKey entityBKey = new EntityBKey( 1, "1" ); - EntityB entityB = new EntityB( entityBKey, entityA ); + EntityBKey entityBKey = new EntityBKey( ENTITY_B_ID1, ENTITY_B_ID2 ); + EntityB entityB = new EntityB( entityBKey, entityA, ENTITY_B_NAME ); session.persist( entityA ); session.persist( entityB ); @@ -59,16 +71,19 @@ public void tearDown(SessionFactoryScope scope) { public void testFind(SessionFactoryScope scope) { scope.inTransaction( session -> { - EntityAKey entityAKey = new EntityAKey( 1, "1" ); + EntityAKey entityAKey = new EntityAKey( ENTITY_A_ID1, ENTITY_A_ID2 ); EntityA entityA = session.find( EntityA.class, entityAKey ); assertThat( entityA ).isNotNull(); + assertThat( entityA.getName() ).isEqualTo( ENTITY_A_NAME ); EntityB entityB = entityA.getEntityB(); assertThat( entityB ).isNotNull(); EntityBKey key = entityB.getEntityBKey(); - assertThat( key.id1 ).isEqualTo( 1 ); - assertThat( key.id2 ).isEqualTo( "1" ); + assertThat( key.id1 ).isEqualTo( ENTITY_B_ID1 ); + assertThat( key.id2 ).isEqualTo( ENTITY_B_ID2 ); + + assertThat( entityB.getName() ).isEqualTo( ENTITY_B_NAME ); } ); } @@ -77,23 +92,40 @@ public void testFind(SessionFactoryScope scope) { public void testFind2(SessionFactoryScope scope) { scope.inTransaction( session -> { - EntityBKey entityBKey = new EntityBKey( 1, "1" ); + EntityBKey entityBKey = new EntityBKey( ENTITY_B_ID1, ENTITY_B_ID2 ); EntityB entityB = session.find( EntityB.class, entityBKey ); assertThat( entityB ).isNotNull(); + assertThat( entityB.getName() ).isEqualTo( ENTITY_B_NAME ); EntityA entityA = entityB.getEntityA(); assertThat( entityA ).isNotNull(); EntityAKey entityAKey = entityA.getEntityAKey(); - assertThat( entityAKey.id1 ).isEqualTo( 1 ); - assertThat( entityAKey.id2 ).isEqualTo( "1" ); + assertThat( entityAKey.id1 ).isEqualTo( ENTITY_A_ID1 ); + assertThat( entityAKey.id2 ).isEqualTo( ENTITY_A_ID2 ); + + assertThat( entityA.getName() ).isEqualTo( ENTITY_A_NAME ); + } + ); + } + + @Test + public void testNativeQuery2(SessionFactoryScope scope) { + scope.inTransaction( + session -> { + String query = "select b.* from ENTITY_B b"; + List entityBS = session.createNativeQuery( query, EntityB.class ).list(); + assertThat( entityBS.size() ).isEqualTo( 1 ); - assertThat( entityA.getName() ).isEqualTo( "te1" ); + EntityB entityB = entityBS.get( 0 ); + assertThat( entityB.getName()).isEqualTo( ENTITY_B_NAME ); + assertThat( entityB.getEntityA().getName()).isEqualTo( ENTITY_A_NAME ); } ); } @Entity(name = "EntityA") + @Table(name= "ENTITY_A") public static class EntityA { @EmbeddedId @@ -144,10 +176,13 @@ public EntityAKey(Integer id1, String id2) { } @Entity(name = "EntityB") + @Table(name = "ENTITY_B") public static class EntityB { @EmbeddedId private EntityBKey entityBKey; + private String name; + @OneToOne(optional = false, fetch = FetchType.LAZY) @JoinColumns({ @JoinColumn(name = "id1", referencedColumnName = "id1", nullable = false, @@ -160,10 +195,11 @@ public static class EntityB { public EntityB() { } - public EntityB(EntityBKey key, EntityA testEntity) { + public EntityB(EntityBKey key, EntityA testEntity, String name) { this.entityBKey = key; this.entityA = testEntity; testEntity.entityB = this; + this.name = name; } public EntityBKey getEntityBKey() { @@ -173,6 +209,10 @@ public EntityBKey getEntityBKey() { public EntityA getEntityA() { return entityA; } + + public String getName() { + return name; + } } @Embeddable