diff --git a/hibernate-core/src/main/java/org/hibernate/engine/spi/SubselectFetch.java b/hibernate-core/src/main/java/org/hibernate/engine/spi/SubselectFetch.java index c01aecb684..e764b62d2c 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/spi/SubselectFetch.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/spi/SubselectFetch.java @@ -13,15 +13,12 @@ import java.util.Map; import java.util.Set; import org.hibernate.spi.NavigablePath; -import org.hibernate.sql.ast.tree.expression.JdbcParameter; import org.hibernate.sql.ast.tree.from.TableGroup; import org.hibernate.sql.ast.tree.select.QuerySpec; import org.hibernate.sql.ast.tree.select.SelectStatement; import org.hibernate.sql.exec.spi.JdbcParameterBindings; import org.hibernate.sql.exec.spi.JdbcParametersList; -import org.hibernate.sql.results.graph.DomainResult; import org.hibernate.sql.results.graph.entity.LoadingEntityEntry; -import org.hibernate.sql.results.graph.entity.internal.EntityResultInitializer; /** * Encapsulates details related to entities which contain sub-select-fetchable @@ -151,8 +148,7 @@ public class SubselectFetch { public void addKey(EntityKey key, LoadingEntityEntry entry) { if ( batchFetchQueue.getSession().getLoadQueryInfluencers() - .hasSubselectLoadableCollections( entry.getDescriptor() ) - && shouldAddSubselectFetch( entry ) ) { + .hasSubselectLoadableCollections( entry.getDescriptor() ) ) { final SubselectFetch subselectFetch = subselectFetches.computeIfAbsent( entry.getEntityInitializer().getNavigablePath(), navigablePath -> new SubselectFetch( @@ -169,23 +165,5 @@ public class SubselectFetch { batchFetchQueue.addSubselect( key, subselectFetch ); } } - - private boolean shouldAddSubselectFetch(LoadingEntityEntry entry) { - if ( entry.getEntityInitializer() instanceof EntityResultInitializer ) { - return true; - } - else { - final NavigablePath entityInitializerParent = entry.getEntityInitializer().getNavigablePath().getParent(); - - // We want to add only the collections of the loading entities - for ( DomainResult domainResult : loadingSqlAst.getDomainResultDescriptors() ) { - if ( domainResult.getNavigablePath().equals( entityInitializerParent ) ) { - return true; - } - } - - return false; - } - } } } diff --git a/hibernate-core/src/main/java/org/hibernate/sql/exec/spi/ExecutionContext.java b/hibernate-core/src/main/java/org/hibernate/sql/exec/spi/ExecutionContext.java index 8f30d4b7e5..6983137e90 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/exec/spi/ExecutionContext.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/exec/spi/ExecutionContext.java @@ -60,10 +60,22 @@ public interface ExecutionContext { return null; } + /** + * + * @param entityKey + * @param entry + * + * @deprecated use {@link #registerSubselect(EntityKey, LoadingEntityEntry)} instead. + */ + @Deprecated default void registerLoadingEntityEntry(EntityKey entityKey, LoadingEntityEntry entry) { // by default do nothing } + default void registerSubselect(EntityKey entityKey, LoadingEntityEntry entry) { + registerLoadingEntityEntry( entityKey, entry ); + } + /** * Hook to allow delaying calls to {@link LogicalConnectionImplementor#afterStatement()}. * Mainly used in the case of batching and multi-table mutations diff --git a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/embeddable/internal/NestedRowProcessingState.java b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/embeddable/internal/NestedRowProcessingState.java index 9a00c4174c..2dd3a58e00 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/embeddable/internal/NestedRowProcessingState.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/embeddable/internal/NestedRowProcessingState.java @@ -8,6 +8,7 @@ package org.hibernate.sql.results.graph.embeddable.internal; import org.hibernate.engine.spi.CollectionKey; import org.hibernate.engine.spi.EntityKey; +import org.hibernate.engine.spi.SubselectFetch; import org.hibernate.metamodel.mapping.EntityMappingType; import org.hibernate.query.spi.QueryOptions; import org.hibernate.query.spi.QueryParameterBindings; diff --git a/hibernate-core/src/main/java/org/hibernate/sql/results/internal/StandardRowReader.java b/hibernate-core/src/main/java/org/hibernate/sql/results/internal/StandardRowReader.java index d8af16c202..81e31feb7e 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/results/internal/StandardRowReader.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/results/internal/StandardRowReader.java @@ -83,7 +83,6 @@ public class StandardRowReader implements RowReader { @Override public T readRow(RowProcessingState rowProcessingState, JdbcValuesSourceProcessingOptions options) { LoadingLogger.LOGGER.trace( "StandardRowReader#readRow" ); - coordinateInitializers( rowProcessingState ); final Object[] resultRow = new Object[ assemblerCount ]; @@ -112,6 +111,7 @@ public class StandardRowReader implements RowReader { @Override public void finishUp(JdbcValuesSourceProcessingState processingState) { + processingState.registerSubselect(); initializers.endLoading( processingState.getExecutionContext() ); } diff --git a/hibernate-core/src/main/java/org/hibernate/sql/results/jdbc/internal/JdbcValuesSourceProcessingStateStandardImpl.java b/hibernate-core/src/main/java/org/hibernate/sql/results/jdbc/internal/JdbcValuesSourceProcessingStateStandardImpl.java index 3c602a5edb..dc18003bd4 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/results/jdbc/internal/JdbcValuesSourceProcessingStateStandardImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/results/jdbc/internal/JdbcValuesSourceProcessingStateStandardImpl.java @@ -20,6 +20,8 @@ import org.hibernate.event.spi.EventSource; import org.hibernate.event.spi.PostLoadEvent; import org.hibernate.event.spi.PostLoadEventListener; import org.hibernate.event.spi.PreLoadEvent; +import org.hibernate.internal.CoreLogging; +import org.hibernate.internal.CoreMessageLogger; import org.hibernate.query.spi.QueryOptions; import org.hibernate.sql.exec.spi.Callback; import org.hibernate.sql.exec.spi.ExecutionContext; @@ -36,6 +38,8 @@ import org.hibernate.sql.results.jdbc.spi.JdbcValuesSourceProcessingState; */ public class JdbcValuesSourceProcessingStateStandardImpl implements JdbcValuesSourceProcessingState { + private static final CoreMessageLogger LOG = CoreLogging.messageLogger( JdbcValuesSourceProcessingStateStandardImpl.class ); + private final ExecutionContext executionContext; private final JdbcValuesSourceProcessingOptions processingOptions; @@ -97,7 +101,6 @@ public class JdbcValuesSourceProcessingStateStandardImpl implements JdbcValuesSo if ( loadingEntityMap == null ) { loadingEntityMap = new HashMap<>(); } - executionContext.registerLoadingEntityEntry( entityKey, loadingEntry ); loadingEntityMap.put( entityKey, loadingEntry ); } @@ -137,6 +140,22 @@ public class JdbcValuesSourceProcessingStateStandardImpl implements JdbcValuesSo return loadingCollectionMap.get( key ); } + @Override + public void registerSubselect() { + if ( loadingEntityMap != null && loadingEntityMap.size() > 1 ) { + loadingEntityMap.forEach( + (entityKey, loadingEntityEntry) -> + executionContext.registerSubselect( entityKey, loadingEntityEntry ) + ); + } + else { + LOG.tracef( + "Skipping create subselects because there are fewer than 2 results, so query by key is more efficient.", + getClass().getName() + ); + } + } + @Override public void registerLoadingCollection(CollectionKey key, LoadingCollectionEntry loadingCollectionEntry) { if ( loadingCollectionMap == null ) { diff --git a/hibernate-core/src/main/java/org/hibernate/sql/results/jdbc/spi/JdbcValuesSourceProcessingState.java b/hibernate-core/src/main/java/org/hibernate/sql/results/jdbc/spi/JdbcValuesSourceProcessingState.java index 8de91f7e84..f0ee56ba93 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/results/jdbc/spi/JdbcValuesSourceProcessingState.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/results/jdbc/spi/JdbcValuesSourceProcessingState.java @@ -80,5 +80,8 @@ public interface JdbcValuesSourceProcessingState { CollectionKey collectionKey, LoadingCollectionEntry loadingCollectionEntry); + default void registerSubselect() { + } + void finishUp(); } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/fetch/depth/DepthOneBatchTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/fetch/depth/DepthOneBatchTest.java index fda1c5e802..1e126b1bc8 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/fetch/depth/DepthOneBatchTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/fetch/depth/DepthOneBatchTest.java @@ -104,7 +104,7 @@ public class DepthOneBatchTest { ); assertThat( executedQueries.get( 4 ).toLowerCase() ).isEqualTo( - "select u1_0.group_id,u1_1.user_id,a1_0.agency_id,a1_0.agency_txt,u1_1.user_name from group_user u1_0 join user_table u1_1 on u1_1.user_id=u1_0.user_id left join agency_table a1_0 on a1_0.agency_id=u1_1.agency_id where u1_0.group_id in (select g1_0.group_id from group_table g1_0 where g1_0.agency_id=?)" + "select u1_0.group_id,u1_1.user_id,a1_0.agency_id,a1_0.agency_txt,u1_1.user_name from group_user u1_0 join user_table u1_1 on u1_1.user_id=u1_0.user_id left join agency_table a1_0 on a1_0.agency_id=u1_1.agency_id where u1_0.group_id=?" ); } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/fetch/depth/DepthOneTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/fetch/depth/DepthOneTest.java index 9c13529d1a..461736fcd1 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/fetch/depth/DepthOneTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/fetch/depth/DepthOneTest.java @@ -100,7 +100,7 @@ public class DepthOneTest { ); assertThat( executedQueries.get( 3 ).toLowerCase() ).isEqualTo( - "select u1_0.group_id,u1_1.user_id,a1_0.agency_id,a1_0.agency_txt,u1_1.user_name from group_user u1_0 join user_table u1_1 on u1_1.user_id=u1_0.user_id left join agency_table a1_0 on a1_0.agency_id=u1_1.agency_id where u1_0.group_id in (select g1_0.group_id from group_table g1_0 where g1_0.agency_id=?)" + "select u1_0.group_id,u1_1.user_id,a1_0.agency_id,a1_0.agency_txt,u1_1.user_name from group_user u1_0 join user_table u1_1 on u1_1.user_id=u1_0.user_id left join agency_table a1_0 on a1_0.agency_id=u1_1.agency_id where u1_0.group_id=?" ); assertThat( executedQueries.get( 4 ).toLowerCase() ).isEqualTo( diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/fetch/subselect/SubselectOneToManyTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/fetch/subselect/SubselectOneToManyTest.java index 238699ece8..72c86bac35 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/fetch/subselect/SubselectOneToManyTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/fetch/subselect/SubselectOneToManyTest.java @@ -109,7 +109,7 @@ public class SubselectOneToManyTest { assertThat( parent.getChildren() ).hasSize( 2 ); statementInspector.assertExecutedCount( 3 ); // 1 query for parent, 1 for grandparent, 1 for children statementInspector.assertNumberOfOccurrenceInQuery( 0, "join", 1 ); - statementInspector.assertNumberOfOccurrenceInQuery( 2, "join", 1 ); + statementInspector.assertNumberOfOccurrenceInQuery( 2, "join", 0 ); } ); }