From f54105cc51fd8237f61bee595af169b8265613c7 Mon Sep 17 00:00:00 2001 From: Andrea Boriero Date: Thu, 26 Nov 2020 17:30:34 +0100 Subject: [PATCH] Fix issue with fetch for hql query --- .../query/results/FromClauseAccessImpl.java | 13 - .../sqm/sql/BaseSqmToSqlAstConverter.java | 39 +- .../query/sqm/sql/FromClauseIndex.java | 11 +- .../ast/spi/SimpleFromClauseAccessImpl.java | 6 + ...bstractImmediateCollectionInitializer.java | 78 ++- .../AbstractEmbeddableInitializer.java | 13 +- .../internal/EmbeddableAssembler.java | 2 + .../hibernate/test/cid/CompositeIdTest.java | 519 +++++++++--------- 8 files changed, 362 insertions(+), 319 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/query/results/FromClauseAccessImpl.java b/hibernate-core/src/main/java/org/hibernate/query/results/FromClauseAccessImpl.java index 4d65fef7eb..ab2b998998 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/results/FromClauseAccessImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/query/results/FromClauseAccessImpl.java @@ -18,17 +18,12 @@ import org.hibernate.sql.ast.tree.from.TableGroup; * @author Steve Ebersole */ public class FromClauseAccessImpl implements FromClauseAccess { - private List rootTableGroups; private Map tableGroupBySqlAlias; private Map tableGroupByPath; public FromClauseAccessImpl() { } - public List getRootTableGroups() { - return rootTableGroups; - } - public TableGroup getByAlias(String alias) { final TableGroup byAlias = findByAlias( alias ); if ( byAlias == null ) { @@ -45,10 +40,6 @@ public class FromClauseAccessImpl implements FromClauseAccess { } } - if ( rootTableGroups != null && rootTableGroups.size() == 1 ) { - return rootTableGroups.get( 0 ); - } - return null; } @@ -61,10 +52,6 @@ public class FromClauseAccessImpl implements FromClauseAccess { } } - if ( rootTableGroups != null && rootTableGroups.size() == 1 ) { - return rootTableGroups.get( 0 ); - } - return null; } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/sql/BaseSqmToSqlAstConverter.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/sql/BaseSqmToSqlAstConverter.java index ae13e2e283..69eb711f1b 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/sql/BaseSqmToSqlAstConverter.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/sql/BaseSqmToSqlAstConverter.java @@ -8,6 +8,7 @@ package org.hibernate.query.sqm.sql; import java.util.ArrayList; import java.util.Collections; +import java.util.HashMap; import java.util.IdentityHashMap; import java.util.List; import java.util.Map; @@ -249,6 +250,7 @@ public abstract class BaseSqmToSqlAstConverter private final QueryParameterBindings domainParameterBindings; private final Map,Supplier>> jpaCriteriaParamResolutions; + private Map pluralPersisterElementNavigablePathByFullPath = new HashMap<>(); private final SqlAliasBaseManager sqlAliasBaseManager = new SqlAliasBaseManager(); @@ -673,10 +675,12 @@ public abstract class BaseSqmToSqlAstConverter if ( log.isTraceEnabled() ) { log.tracef( "Visiting explicit joins for `%s`", sqmFrom.getNavigablePath() ); } - sqmFrom.visitSqmJoins( - sqmJoin -> consumeExplicitJoin( sqmJoin, lhsTableGroup ) + sqmJoin -> { + consumeExplicitJoin( sqmJoin, lhsTableGroup ); + } ); + pluralPersisterElementNavigablePathByFullPath.clear(); } @SuppressWarnings("WeakerAccess") @@ -702,6 +706,8 @@ public abstract class BaseSqmToSqlAstConverter final TableGroupJoin joinedTableGroupJoin; final TableGroup joinedTableGroup; + final NavigablePath sqmJoinNavigablePath = sqmJoin.getNavigablePath(); + final NavigablePath parentNavigablePath = sqmJoinNavigablePath.getParent(); if ( pathSource instanceof PluralPersistentAttribute ) { final ModelPart pluralPart = lhsTableGroup.getModelPart().findSubPart( sqmJoin.getReferencedPathSource().getPathName(), @@ -712,7 +718,22 @@ public abstract class BaseSqmToSqlAstConverter final PluralAttributeMapping pluralAttributeMapping = (PluralAttributeMapping) pluralPart; - final NavigablePath elementPath = sqmJoin.getNavigablePath().append( CollectionPart.Nature.ELEMENT.getName() ); + NavigablePath elementPath; + if ( parentNavigablePath == null ) { + elementPath = sqmJoinNavigablePath.append( CollectionPart.Nature.ELEMENT.getName() ); + pluralPersisterElementNavigablePathByFullPath.put( sqmJoin.getNavigablePath().getFullPath(), elementPath ); + } + else { + final NavigablePath elementNavigablePath = pluralPersisterElementNavigablePathByFullPath.get( parentNavigablePath.getFullPath() ); + if ( elementNavigablePath == null ) { + elementPath = sqmJoinNavigablePath.append( CollectionPart.Nature.ELEMENT.getName() ); + pluralPersisterElementNavigablePathByFullPath.put( sqmJoin.getNavigablePath().getFullPath(), elementPath ); + } + else { + elementPath = elementNavigablePath.append( pluralAttributeMapping.getPartName() ); + pluralPersisterElementNavigablePathByFullPath.put( sqmJoin.getNavigablePath().getFullPath(), elementPath.append( CollectionPart.Nature.ELEMENT.getName() ) ); + } + } joinedTableGroupJoin = pluralAttributeMapping.createTableGroupJoin( elementPath, @@ -726,7 +747,7 @@ public abstract class BaseSqmToSqlAstConverter lhsTableGroup.addTableGroupJoin( joinedTableGroupJoin ); - fromClauseIndex.register( sqmJoin, joinedTableGroup ); + fromClauseIndex.register( sqmJoin, joinedTableGroup, elementPath ); fromClauseIndex.registerTableGroup( elementPath, joinedTableGroup ); } else if ( pathSource instanceof EmbeddedSqmPathSource ) { @@ -740,10 +761,10 @@ public abstract class BaseSqmToSqlAstConverter final NavigablePath joinedPath; final String explicitAlias = sqmJoin.getExplicitAlias(); if ( explicitAlias == null ) { - joinedPath = sqmJoin.getNavigablePath(); + joinedPath = sqmJoinNavigablePath; } else { - joinedPath = sqmJoin.getNavigablePath().getParent().append( sqmJoin.getAttribute().getName() ); + joinedPath = parentNavigablePath.append( sqmJoin.getAttribute().getName() ); } joinedTableGroupJoin = ( (TableGroupJoinProducer) joinedPart ).createTableGroupJoin( joinedPath, @@ -780,10 +801,10 @@ public abstract class BaseSqmToSqlAstConverter final NavigablePath joinedPath; final String explicitAlias = sqmJoin.getExplicitAlias(); if ( explicitAlias == null ) { - joinedPath = sqmJoin.getNavigablePath(); + joinedPath = sqmJoinNavigablePath; } else { - joinedPath = sqmJoin.getNavigablePath().getParent().append( sqmJoin.getAttribute().getName() ); + joinedPath = parentNavigablePath.append( sqmJoin.getAttribute().getName() ); } joinedTableGroupJoin = ( (TableGroupJoinProducer) joinedPart ).createTableGroupJoin( @@ -806,7 +827,7 @@ public abstract class BaseSqmToSqlAstConverter // add any additional join restrictions if ( sqmJoin.getJoinPredicate() != null ) { if ( sqmJoin.isFetched() ) { - QueryLogging.QUERY_MESSAGE_LOGGER.debugf( "Join fetch [" + sqmJoin.getNavigablePath() + "] is restricted" ); + QueryLogging.QUERY_MESSAGE_LOGGER.debugf( "Join fetch [" + sqmJoinNavigablePath + "] is restricted" ); } if ( joinedTableGroupJoin == null ) { diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/sql/FromClauseIndex.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/sql/FromClauseIndex.java index a4d8f33603..5c2e8e534d 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/sql/FromClauseIndex.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/sql/FromClauseIndex.java @@ -38,6 +38,10 @@ public class FromClauseIndex extends SimpleFromClauseAccessImpl { } public void register(SqmPath sqmPath, TableGroup tableGroup) { + register( sqmPath, tableGroup, null ); + } + + public void register(SqmPath sqmPath, TableGroup tableGroup, NavigablePath identifierForTableGroup) { registerTableGroup( sqmPath.getNavigablePath(), tableGroup ); if ( sqmPath.getExplicitAlias() != null ) { @@ -54,17 +58,20 @@ public class FromClauseIndex extends SimpleFromClauseAccessImpl { if ( sqmPath instanceof SqmAttributeJoin ) { final SqmAttributeJoin sqmJoin = (SqmAttributeJoin) sqmPath; if ( sqmJoin.isFetched() ) { - registerJoinFetch( sqmJoin ); + registerJoinFetch( sqmJoin, identifierForTableGroup ); } } } - private void registerJoinFetch(SqmAttributeJoin sqmJoin) { + private void registerJoinFetch(SqmAttributeJoin sqmJoin, NavigablePath identifierForTableGroup) { if ( fetchesByPath == null ) { fetchesByPath = new HashMap<>(); } NavigablePath navigablePath = sqmJoin.getNavigablePath(); fetchesByPath.put( navigablePath.getIdentifierForTableGroup(), sqmJoin ); + if ( identifierForTableGroup != null ) { + fetchesByPath.put( identifierForTableGroup.getIdentifierForTableGroup(), sqmJoin ); + } } public boolean isResolved(SqmFrom fromElement) { diff --git a/hibernate-core/src/main/java/org/hibernate/sql/ast/spi/SimpleFromClauseAccessImpl.java b/hibernate-core/src/main/java/org/hibernate/sql/ast/spi/SimpleFromClauseAccessImpl.java index fddc289448..85a8710675 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/ast/spi/SimpleFromClauseAccessImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/ast/spi/SimpleFromClauseAccessImpl.java @@ -31,6 +31,12 @@ public class SimpleFromClauseAccessImpl implements FromClauseAccess { @Override public void registerTableGroup(NavigablePath navigablePath, TableGroup tableGroup) { + SqlTreeCreationLogger.LOGGER.debugf( + "Registration of TableGroup [%s] with identifierForTableGroup [%s] for NavigablePath [%s] ", + tableGroup, + tableGroup.getNavigablePath().getIdentifierForTableGroup(), + navigablePath.getIdentifierForTableGroup() + ); final TableGroup previous = tableGroupMap.put( navigablePath.getIdentifierForTableGroup(), tableGroup ); if ( previous != null ) { SqlTreeCreationLogger.LOGGER.debugf( diff --git a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/collection/internal/AbstractImmediateCollectionInitializer.java b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/collection/internal/AbstractImmediateCollectionInitializer.java index b69b2e124d..34650bbc32 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/collection/internal/AbstractImmediateCollectionInitializer.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/collection/internal/AbstractImmediateCollectionInitializer.java @@ -78,13 +78,13 @@ public abstract class AbstractImmediateCollectionInitializer extends AbstractCol return; } - if ( CollectionLoadingLogger.TRACE_ENABLED ) { - CollectionLoadingLogger.INSTANCE.tracef( - "(%s) Beginning Initializer#resolveInstance for collection : %s", - getSimpleConcreteImplName(), - LoggingHelper.toLoggableString( getNavigablePath(), collectionKey.getKey() ) - ); - } +// if ( CollectionLoadingLogger.TRACE_ENABLED ) { +// CollectionLoadingLogger.INSTANCE.tracef( +// "(%s) Beginning Initializer#resolveInstance for collection : %s", +// getSimpleConcreteImplName(), +// LoggingHelper.toLoggableString( getNavigablePath(), collectionKey.getKey() ) +// ); +// } // determine the PersistentCollection instance to use and whether // we (this initializer) is responsible for loading its state @@ -195,14 +195,14 @@ public abstract class AbstractImmediateCollectionInitializer extends AbstractCol session ); - if ( CollectionLoadingLogger.DEBUG_ENABLED ) { - CollectionLoadingLogger.INSTANCE.debugf( - "(%s) Created new collection wrapper [%s] : %s", - getSimpleConcreteImplName(), - LoggingHelper.toLoggableString( getNavigablePath(), collectionKey.getKey() ), - toLoggableString( collectionInstance ) - ); - } +// if ( CollectionLoadingLogger.DEBUG_ENABLED ) { +// CollectionLoadingLogger.INSTANCE.debugf( +// "(%s) Created new collection wrapper [%s] : %s", +// getSimpleConcreteImplName(), +// LoggingHelper.toLoggableString( getNavigablePath(), collectionKey.getKey() ), +// toLoggableString( collectionInstance ) +// ); +// } persistenceContext.addUninitializedCollection( collectionDescriptor, collectionInstance, collectionKey.getKey() ); @@ -210,14 +210,14 @@ public abstract class AbstractImmediateCollectionInitializer extends AbstractCol } if ( responsibility != null ) { - if ( CollectionLoadingLogger.DEBUG_ENABLED ) { - CollectionLoadingLogger.INSTANCE.debugf( - "(%s) Responsible for loading collection [%s] : %s", - getSimpleConcreteImplName(), - LoggingHelper.toLoggableString( getNavigablePath(), collectionKey.getKey() ), - toLoggableString( collectionInstance ) - ); - } +// if ( CollectionLoadingLogger.DEBUG_ENABLED ) { +// CollectionLoadingLogger.INSTANCE.debugf( +// "(%s) Responsible for loading collection [%s] : %s", +// getSimpleConcreteImplName(), +// LoggingHelper.toLoggableString( getNavigablePath(), collectionKey.getKey() ), +// toLoggableString( collectionInstance ) +// ); +// } if ( getParentAccess() != null ) { getParentAccess().registerResolutionListener( @@ -287,28 +287,12 @@ public abstract class AbstractImmediateCollectionInitializer extends AbstractCol collectionAttributeMapping.getCollectionDescriptor(), keyContainerValue ); - - if ( CollectionLoadingLogger.DEBUG_ENABLED ) { - CollectionLoadingLogger.INSTANCE.debugf( - "(%s) Current row collection key : %s", - getSimpleConcreteImplName(), - LoggingHelper.toLoggableString( getNavigablePath(), this.collectionKey.getKey() ) - ); - } } else if ( keyCollectionValue != null ) { this.collectionKey = new CollectionKey( collectionAttributeMapping.getCollectionDescriptor(), keyCollectionValue ); - - if ( CollectionLoadingLogger.DEBUG_ENABLED ) { - CollectionLoadingLogger.INSTANCE.debugf( - "(%s) Current row collection key : %s", - getSimpleConcreteImplName(), - LoggingHelper.toLoggableString( getNavigablePath(), this.collectionKey.getKey() ) - ); - } } else { this.collectionKey = new CollectionKey( @@ -351,14 +335,14 @@ public abstract class AbstractImmediateCollectionInitializer extends AbstractCol if ( collectionValueKey != null ) { // the row contains an element in the collection... - if ( CollectionLoadingLogger.DEBUG_ENABLED ) { - CollectionLoadingLogger.INSTANCE.debugf( - "(%s) Reading element from row for collection [%s] -> %s", - getSimpleConcreteImplName(), - LoggingHelper.toLoggableString( getNavigablePath(), collectionKey.getKey() ), - toLoggableString( collectionInstance ) - ); - } +// if ( CollectionLoadingLogger.DEBUG_ENABLED ) { +// CollectionLoadingLogger.INSTANCE.debugf( +// "(%s) Reading element from row for collection [%s] -> %s", +// getSimpleConcreteImplName(), +// LoggingHelper.toLoggableString( getNavigablePath(), collectionKey.getKey() ), +// toLoggableString( collectionInstance ) +// ); +// } responsibility.load( loadingState -> readCollectionRow( collectionKey, loadingState, rowProcessingState ) diff --git a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/embeddable/AbstractEmbeddableInitializer.java b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/embeddable/AbstractEmbeddableInitializer.java index df8a0663df..50a2c5fcaf 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/embeddable/AbstractEmbeddableInitializer.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/embeddable/AbstractEmbeddableInitializer.java @@ -40,6 +40,8 @@ public abstract class AbstractEmbeddableInitializer extends AbstractFetchParentA private final Object[] resolvedValues; private final boolean createEmptyCompositesEnabled; private Object compositeInstance; + private boolean keyResolved; + private boolean instanceResolved; @SuppressWarnings("WeakerAccess") @@ -93,6 +95,9 @@ public abstract class AbstractEmbeddableInitializer extends AbstractFetchParentA @Override public void resolveKey(RowProcessingState rowProcessingState) { + if(keyResolved){ + return; + } final PropertyAccess parentInjectionPropertyAccess = embeddedModelPartDescriptor.getParentInjectionAttributePropertyAccess(); final FetchParentAccess fetchParentAccess = getFetchParentAccess(); @@ -113,14 +118,19 @@ public abstract class AbstractEmbeddableInitializer extends AbstractFetchParentA } ); } + keyResolved = true; } @Override public void resolveInstance(RowProcessingState rowProcessingState) { + if ( instanceResolved ) { + return; + } compositeInstance = embeddedModelPartDescriptor.getEmbeddableTypeDescriptor() .getRepresentationStrategy() .getInstantiator() .instantiate( rowProcessingState.getSession().getFactory() ); + instanceResolved = true; EmbeddableLoadingLogger.INSTANCE.debugf( "Created composite instance [%s] : %s", navigablePath, @@ -192,7 +202,8 @@ public abstract class AbstractEmbeddableInitializer extends AbstractFetchParentA @Override public void finishUpRow(RowProcessingState rowProcessingState) { compositeInstance = null; - + keyResolved = true; + instanceResolved = false; clearParentResolutionListeners(); } diff --git a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/embeddable/internal/EmbeddableAssembler.java b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/embeddable/internal/EmbeddableAssembler.java index 75c83bc85a..9bb6486f67 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/embeddable/internal/EmbeddableAssembler.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/embeddable/internal/EmbeddableAssembler.java @@ -30,6 +30,8 @@ public class EmbeddableAssembler implements DomainResultAssembler { @Override public Object assemble(RowProcessingState rowProcessingState, JdbcValuesSourceProcessingOptions options) { + initializer.resolveKey( rowProcessingState ); + initializer.resolveInstance( rowProcessingState ); return initializer.getCompositeInstance(); } diff --git a/hibernate-core/src/test/java/org/hibernate/test/cid/CompositeIdTest.java b/hibernate-core/src/test/java/org/hibernate/test/cid/CompositeIdTest.java index 98854f5119..e47c2690a9 100755 --- a/hibernate-core/src/test/java/org/hibernate/test/cid/CompositeIdTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/cid/CompositeIdTest.java @@ -6,275 +6,300 @@ */ package org.hibernate.test.cid; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - import java.math.BigDecimal; import java.util.Calendar; -import java.util.Collections; import java.util.Iterator; import java.util.List; -import javax.persistence.PersistenceException; - import org.hibernate.Hibernate; -import org.hibernate.Session; -import org.hibernate.Transaction; -import org.hibernate.dialect.Oracle8iDialect; -import org.hibernate.dialect.SQLServerDialect; -import org.hibernate.exception.SQLGrammarException; -import org.hibernate.testing.SkipForDialect; -import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase; -import org.junit.Test; +import org.hibernate.testing.jdbc.SQLStatementInspector; +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.AfterEach; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; /** * @author Gavin King */ -public class CompositeIdTest extends BaseCoreFunctionalTestCase { - @Override - public String[] getMappings() { - return new String[] { "cid/Customer.hbm.xml", "cid/Order.hbm.xml", "cid/LineItem.hbm.xml", "cid/Product.hbm.xml" }; - } - - @Test - public void testQuery() { - Session s = openSession(); - Transaction t = s.beginTransaction(); - s.createQuery("from LineItem ol where ol.order.id.customerId = 'C111'").list(); - t.commit(); - s.close(); - } - - @Test - public void testCompositeIds() { - Session s = openSession(); - Transaction t = s.beginTransaction(); - - Product p = new Product(); - p.setProductId("A123"); - p.setDescription("nipple ring"); - p.setPrice( new BigDecimal(1.0) ); - p.setNumberAvailable(1004); - s.persist(p); - - Product p2 = new Product(); - p2.setProductId("X525"); - p2.setDescription("nose stud"); - p2.setPrice( new BigDecimal(3.0) ); - p2.setNumberAvailable(105); - s.persist(p2); - - Customer c = new Customer(); - c.setAddress("St Kilda Rd, MEL, 3000"); - c.setName("Virginia"); - c.setCustomerId("C111"); - s.persist(c); - - Order o = new Order(c); - o.setOrderDate( Calendar.getInstance() ); - LineItem li = new LineItem(o, p); - li.setQuantity(2); - - t.commit(); - s.close(); - - s = openSession(); - t = s.beginTransaction(); - o = (Order) s.get( Order.class, new Order.Id("C111", 0) ); - assertEquals( o.getTotal().intValue(), 2 ); - o.getCustomer().getName(); - t.commit(); - s.close(); - - s = openSession(); - t = s.beginTransaction(); - s.createQuery("from Customer c left join fetch c.orders o left join fetch o.lineItems li left join fetch li.product p").list(); - t.commit(); - s.close(); - - s = openSession(); - t = s.beginTransaction(); - s.createQuery("from Order o left join fetch o.lineItems li left join fetch li.product p").list(); - t.commit(); - s.close(); - - s = openSession(); - t = s.beginTransaction(); - Iterator iter = s.createQuery("select o.id, li.id from Order o join o.lineItems li").list().iterator(); - while ( iter.hasNext() ) { - Object[] stuff = (Object[]) iter.next(); - assertTrue(stuff.length==2); +@DomainModel( + xmlMappings = { + "org/hibernate/test/cid/Customer.hbm.xml", + "org/hibernate/test/cid/Order.hbm.xml", + "org/hibernate/test/cid/LineItem.hbm.xml", + "org/hibernate/test/cid/Product.hbm.xml" } - iter = s.createQuery("from Order o join o.lineItems li").list().iterator(); - while ( iter.hasNext() ) { - Object[] stuff = (Object[]) iter.next(); - assertTrue(stuff.length==2); - } - t.commit(); - s.close(); - - s = openSession(); - t = s.beginTransaction(); - c = (Customer) s.get( Customer.class, "C111" ); - Order o2 = new Order(c); - o2.setOrderDate( Calendar.getInstance() ); - s.flush(); - LineItem li2 = new LineItem(o2, p2); - li2.setQuantity(5); - List bigOrders = s.createQuery("from Order o where o.total>10.0").list(); - assertEquals( bigOrders.size(), 1 ); - t.commit(); - s.close(); - - s = openSession(); - t = s.beginTransaction(); - s.createQuery("delete from LineItem").executeUpdate(); - s.createQuery("delete from Order").executeUpdate(); - s.createQuery("delete from Customer").executeUpdate(); - s.createQuery("delete from Product").executeUpdate(); - t.commit(); - s.close(); +) +@SessionFactory(statementInspectorClass = SQLStatementInspector.class) +public class CompositeIdTest { + + @AfterEach + public void tearDown(SessionFactoryScope scope) { + scope.inTransaction( + session -> { + session.createQuery( "delete from LineItem" ).executeUpdate(); + session.createQuery( "delete from Order" ).executeUpdate(); + session.createQuery( "delete from Customer" ).executeUpdate(); + session.createQuery( "delete from Product" ).executeUpdate(); + } + ); } @Test - public void testNonLazyFetch() { - Session s = openSession(); - Transaction t = s.beginTransaction(); - - Product p = new Product(); - p.setProductId("A123"); - p.setDescription("nipple ring"); - p.setPrice( new BigDecimal(1.0) ); - p.setNumberAvailable(1004); - s.persist(p); - - Product p2 = new Product(); - p2.setProductId("X525"); - p2.setDescription("nose stud"); - p2.setPrice( new BigDecimal(3.0) ); - p2.setNumberAvailable(105); - s.persist(p2); - - Customer c = new Customer(); - c.setAddress("St Kilda Rd, MEL, 3000"); - c.setName("Virginia"); - c.setCustomerId("C111"); - s.persist(c); - - Order o = new Order(c); - o.setOrderDate( Calendar.getInstance() ); - LineItem li = new LineItem(o, p); - li.setQuantity(2); - - t.commit(); - s.close(); - - s = openSession(); - t = s.beginTransaction(); - o = (Order) s.get( Order.class, new Order.Id("C111", 0) ); - assertEquals( o.getTotal().intValue(), 2 ); - o.getCustomer().getName(); - t.commit(); - s.close(); - - s = openSession(); - t = s.beginTransaction(); - o = (Order) s.createQuery("from Order o left join fetch o.lineItems li left join fetch li.product p").uniqueResult(); - assertTrue( Hibernate.isInitialized( o.getLineItems() ) ); - li = (LineItem) o.getLineItems().iterator().next(); - assertTrue( Hibernate.isInitialized( li ) ); - assertTrue( Hibernate.isInitialized( li.getProduct() ) ); - t.commit(); - s.close(); - - s = openSession(); - t = s.beginTransaction(); - o = (Order) s.createQuery("from Order o").uniqueResult(); - assertTrue( Hibernate.isInitialized( o.getLineItems() ) ); - li = (LineItem) o.getLineItems().iterator().next(); - assertTrue( Hibernate.isInitialized( li ) ); - assertFalse( Hibernate.isInitialized( li.getProduct() ) ); - t.commit(); - s.close(); - - - s = openSession(); - t = s.beginTransaction(); - s.createQuery("delete from LineItem").executeUpdate(); - s.createQuery("delete from Order").executeUpdate(); - s.createQuery("delete from Customer").executeUpdate(); - s.createQuery("delete from Product").executeUpdate(); - t.commit(); - s.close(); - + public void testQuery(SessionFactoryScope scope) { + scope.inTransaction( + session -> + session.createQuery( "from LineItem ol where ol.order.id.customerId = 'C111'" ).list() + ); } @Test - public void testMultipleCollectionFetch() { - Session s = openSession(); - Transaction t = s.beginTransaction(); - + public void testCompositeIds(SessionFactoryScope scope) { Product p = new Product(); - p.setProductId("A123"); - p.setDescription("nipple ring"); - p.setPrice( new BigDecimal(1.0) ); - p.setNumberAvailable(1004); - s.persist(p); - + p.setProductId( "A123" ); + p.setDescription( "nipple ring" ); + p.setPrice( new BigDecimal( 1.0 ) ); + p.setNumberAvailable( 1004 ); + Product p2 = new Product(); - p2.setProductId("X525"); - p2.setDescription("nose stud"); - p2.setPrice( new BigDecimal(3.0) ); - p2.setNumberAvailable(105); - s.persist(p2); - - Customer c = new Customer(); - c.setAddress("St Kilda Rd, MEL, 3000"); - c.setName("Virginia"); - c.setCustomerId("C111"); - s.persist(c); - - Order o = new Order(c); - o.setOrderDate( Calendar.getInstance() ); - LineItem li = new LineItem(o, p); - li.setQuantity(2); - LineItem li2 = new LineItem(o, p2); - li2.setQuantity(3); + p2.setProductId( "X525" ); + p2.setDescription( "nose stud" ); + p2.setPrice( new BigDecimal( 3.0 ) ); + p2.setNumberAvailable( 105 ); - Order o2 = new Order(c); - o2.setOrderDate( Calendar.getInstance() ); - LineItem li3 = new LineItem(o2, p); - li3.setQuantity(1); - LineItem li4 = new LineItem(o2, p2); - li4.setQuantity(1); + scope.inTransaction( + session -> { + session.persist( p ); + session.persist( p2 ); - t.commit(); - s.close(); - - s = openSession(); - t = s.beginTransaction(); - c = (Customer) s.createQuery("from Customer c left join fetch c.orders o left join fetch o.lineItems li left join fetch li.product p").uniqueResult(); - assertTrue( Hibernate.isInitialized( c.getOrders() ) ); - assertEquals( c.getOrders().size(), 2 ); - assertTrue( Hibernate.isInitialized( ( (Order) c.getOrders().get(0) ).getLineItems() ) ); - assertTrue( Hibernate.isInitialized( ( (Order) c.getOrders().get(1) ).getLineItems() ) ); - assertEquals( ( (Order) c.getOrders().get(0) ).getLineItems().size(), 2 ); - assertEquals( ( (Order) c.getOrders().get(1) ).getLineItems().size(), 2 ); - t.commit(); - s.close(); - - s = openSession(); - t = s.beginTransaction(); - s.createQuery("delete from LineItem").executeUpdate(); - s.createQuery("delete from Order").executeUpdate(); - s.createQuery("delete from Customer").executeUpdate(); - s.createQuery("delete from Product").executeUpdate(); - t.commit(); - s.close(); + Customer c = new Customer(); + c.setAddress( "St Kilda Rd, MEL, 3000" ); + c.setName( "Virginia" ); + c.setCustomerId( "C111" ); + session.persist( c ); + + Order o = new Order( c ); + o.setOrderDate( Calendar.getInstance() ); + LineItem li = new LineItem( o, p ); + li.setQuantity( 2 ); + } + ); + + final SQLStatementInspector statementInspector = (SQLStatementInspector) scope.getStatementInspector(); + statementInspector.clear(); + + scope.inTransaction( + session -> { + Order o = session.get( Order.class, new Order.Id( "C111", 0 ) ); + statementInspector.assertExecutedCount( 1 ); + statementInspector.assertNumberOfOccurrenceInQuery( 0,"join", 1 ); + assertEquals( o.getTotal().intValue(), 2 ); + o.getCustomer().getName(); + } + ); + + statementInspector.clear(); + scope.inTransaction( + session -> { + session.createQuery( + "from Customer c left join fetch c.orders o left join fetch o.lineItems li left join fetch li.product p" ) + .list(); + statementInspector.assertExecutedCount( 1 ); + } + ); + + statementInspector.clear(); + scope.inTransaction( + session -> { + session.createQuery( "from Order o left join fetch o.lineItems li left join fetch li.product p" ) + .list(); + statementInspector.assertExecutedCount( 1 ); + } + ); + + statementInspector.clear(); + scope.inTransaction( + session -> { + Iterator iter = session.createQuery( "select o.id, li.id from Order o join o.lineItems li" ) + .list() + .iterator(); + statementInspector.assertExecutedCount( 1 ); + while ( iter.hasNext() ) { + Object[] stuff = (Object[]) iter.next(); + assertTrue( stuff.length == 2 ); + } + statementInspector.assertExecutedCount( 1 ); + statementInspector.clear(); + iter = session.createQuery( "from Order o join o.lineItems li" ).list().iterator(); + statementInspector.assertExecutedCount( 1 ); + while ( iter.hasNext() ) { + Object[] stuff = (Object[]) iter.next(); + assertTrue( stuff.length == 2 ); + } + statementInspector.assertExecutedCount( 1 ); + } + ); + + statementInspector.clear(); + scope.inTransaction( + session -> { + Customer c = session.get( Customer.class, "C111" ); + statementInspector.assertExecutedCount( 1 ); + statementInspector.assertNumberOfOccurrenceInQuery( 0,"join", 0 ); + + statementInspector.clear(); + Order o2 = new Order( c ); + o2.setOrderDate( Calendar.getInstance() ); + statementInspector.assertExecutedCount( 2 ); + statementInspector.assertNumberOfOccurrenceInQuery( 0,"join", 0 ); + statementInspector.assertNumberOfOccurrenceInQuery( 1,"join", 0 ); + + statementInspector.clear(); + session.flush(); + statementInspector.assertExecutedCount( 4 ); + statementInspector.assertNumberOfOccurrenceInQuery( 0,"select", 1 ); + statementInspector.assertNumberOfOccurrenceInQuery( 0,"join", 0 ); + statementInspector.assertNumberOfOccurrenceInQuery( 1,"insert", 1 ); + statementInspector.assertNumberOfOccurrenceInQuery( 2,"update", 1 ); + statementInspector.assertNumberOfOccurrenceInQuery( 3,"update", 1 ); + + + LineItem li2 = new LineItem( o2, p2 ); + li2.setQuantity( 5 ); + statementInspector.clear(); + + List bigOrders = session.createQuery( "from Order o where o.total>10.0" ).list(); + statementInspector.assertExecutedCount( 3 ); + statementInspector.assertNumberOfOccurrenceInQuery( 0,"select", 1 ); + statementInspector.assertNumberOfOccurrenceInQuery( 0,"join", 0 ); + statementInspector.assertNumberOfOccurrenceInQuery( 1,"insert", 1 ); + statementInspector.assertNumberOfOccurrenceInQuery( 2,"select", 2 ); + statementInspector.assertNumberOfOccurrenceInQuery( 3,"join", 0 ); + + assertEquals( bigOrders.size(), 1 ); + } + ); } + @Test + public void testNonLazyFetch(SessionFactoryScope scope) { + scope.inTransaction( + session -> { + Product p = new Product(); + p.setProductId( "A123" ); + p.setDescription( "nipple ring" ); + p.setPrice( new BigDecimal( 1.0 ) ); + p.setNumberAvailable( 1004 ); + session.persist( p ); + + Product p2 = new Product(); + p2.setProductId( "X525" ); + p2.setDescription( "nose stud" ); + p2.setPrice( new BigDecimal( 3.0 ) ); + p2.setNumberAvailable( 105 ); + session.persist( p2 ); + + Customer c = new Customer(); + c.setAddress( "St Kilda Rd, MEL, 3000" ); + c.setName( "Virginia" ); + c.setCustomerId( "C111" ); + session.persist( c ); + + Order o = new Order( c ); + o.setOrderDate( Calendar.getInstance() ); + LineItem li = new LineItem( o, p ); + li.setQuantity( 2 ); + } + ); + + scope.inTransaction( + session -> { + Order o = session.get( Order.class, new Order.Id( "C111", 0 ) ); + assertEquals( o.getTotal().intValue(), 2 ); + o.getCustomer().getName(); + } + ); + + scope.inTransaction( + session -> { + Order o = (Order) session.createQuery( + "from Order o left join fetch o.lineItems li left join fetch li.product p" ) + .uniqueResult(); + assertTrue( Hibernate.isInitialized( o.getLineItems() ) ); + LineItem li = (LineItem) o.getLineItems().iterator().next(); + assertTrue( Hibernate.isInitialized( li ) ); + assertTrue( Hibernate.isInitialized( li.getProduct() ) ); + } + ); + + scope.inTransaction( + session -> { + Order o = (Order) session.createQuery( "from Order o" ).uniqueResult(); + assertTrue( Hibernate.isInitialized( o.getLineItems() ) ); + LineItem li = (LineItem) o.getLineItems().iterator().next(); + assertTrue( Hibernate.isInitialized( li ) ); + assertFalse( Hibernate.isInitialized( li.getProduct() ) ); + } + ); + } + + @Test + public void testMultipleCollectionFetch(SessionFactoryScope scope) { + scope.inTransaction( + session -> { + Product p = new Product(); + p.setProductId( "A123" ); + p.setDescription( "nipple ring" ); + p.setPrice( new BigDecimal( 1.0 ) ); + p.setNumberAvailable( 1004 ); + session.persist( p ); + + Product p2 = new Product(); + p2.setProductId( "X525" ); + p2.setDescription( "nose stud" ); + p2.setPrice( new BigDecimal( 3.0 ) ); + p2.setNumberAvailable( 105 ); + session.persist( p2 ); + + Customer c = new Customer(); + c.setAddress( "St Kilda Rd, MEL, 3000" ); + c.setName( "Virginia" ); + c.setCustomerId( "C111" ); + session.persist( c ); + + Order o = new Order( c ); + o.setOrderDate( Calendar.getInstance() ); + LineItem li = new LineItem( o, p ); + li.setQuantity( 2 ); + LineItem li2 = new LineItem( o, p2 ); + li2.setQuantity( 3 ); + + Order o2 = new Order( c ); + o2.setOrderDate( Calendar.getInstance() ); + LineItem li3 = new LineItem( o2, p ); + li3.setQuantity( 1 ); + LineItem li4 = new LineItem( o2, p2 ); + li4.setQuantity( 1 ); + } + ); + + scope.inTransaction( + session -> { + Customer c = (Customer) session.createQuery( + "from Customer c left join fetch c.orders o left join fetch o.lineItems li left join fetch li.product p" ) + .uniqueResult(); + assertTrue( Hibernate.isInitialized( c.getOrders() ) ); + assertEquals( c.getOrders().size(), 2 ); + assertTrue( Hibernate.isInitialized( ( (Order) c.getOrders().get( 0 ) ).getLineItems() ) ); + assertTrue( Hibernate.isInitialized( ( (Order) c.getOrders().get( 1 ) ).getLineItems() ) ); + assertEquals( 2, ( (Order) c.getOrders().get( 0 ) ).getLineItems().size() ); + assertEquals( 2, ( (Order) c.getOrders().get( 1 ) ).getLineItems().size() ); + } + ); + } } -