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 c9319a2c1a..a0622a8fd4 100755 --- a/hibernate-core/src/main/java/org/hibernate/engine/spi/SubselectFetch.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/spi/SubselectFetch.java @@ -34,8 +34,59 @@ public class SubselectFetch { private final QueryParameters queryParameters; private final Map namedParameterLocMap; + /** + * Construct a SubselectFetch instance. The subselect fetch query fragment is generated by + * {@link #createSubselectFetchQueryFragment}. + * + * If the same value for {@code queryParameters} is to be used when constructing multiple + * SubselectFetch objects, then it is preferable to generate the subselect fetch query + * fragment using {@link #createSubselectFetchQueryFragment}, and pass the result as an + * argument to constructor {@link #SubselectFetch(String, String, Loadable, QueryParameters, Set, Map)}. + * + * @param alias - the table alias used in the subselect fetch query fragment + * (to be generated by {@link #createSubselectFetchQueryFragment(QueryParameters)} that + * corresponds to {@code loadable}; + * @param loadable - the {@link Loadable} for the associated entities to be subselect fetched; + * @param queryParameters - the query parameters; + * @param resultingEntityKeys - the {@link EntityKey} objects for the entities to be subselect fetched; + * @param namedParameterLocMap - mapping from named parameter to the parameter index located in the + * subselect fetch query fragment. + * + * @see #SubselectFetch(String, String, Loadable, QueryParameters, Set, Map) + */ public SubselectFetch( - //final String queryString, + final String alias, + final Loadable loadable, + final QueryParameters queryParameters, + final Set resultingEntityKeys, + final Map namedParameterLocMap) { + this( + createSubselectFetchQueryFragment( queryParameters ), + alias, + loadable, + queryParameters, + resultingEntityKeys, + namedParameterLocMap + ); + } + + /** + * Construct a SubselectFetch instance using the provided subselect fetch query fragment, + * {@code subselectFetchQueryFragment}. It is assumed that {@code subselectFetchQueryFragment} + * is the result of calling {@link #createSubselectFetchQueryFragment} with the same value + * provided for {@code queryParameters}. + * + * @param subselectFetchQueryFragment - the subselect fetch query fragment; + * @param alias - the table alias used in {@code subselectFetchQueryFragment} that + * corresponds to {@code loadable}; + * @param loadable - the {@link Loadable} for the associated entities to be subselect fetched; + * @param queryParameters - the query parameters; + * @param resultingEntityKeys - the {@link EntityKey} objects for the entities to be subselect fetched; + * @param namedParameterLocMap - mapping from named parameter to the parameter index located in the + * subselect fetch query fragment. + */ + public SubselectFetch( + final String subselectFetchQueryFragment, final String alias, final Loadable loadable, final QueryParameters queryParameters, @@ -47,16 +98,28 @@ public SubselectFetch( this.loadable = loadable; this.alias = alias; + this.queryString = subselectFetchQueryFragment; + } + + /** + * Create the subselect fetch query fragment for the provided {@link QueryParameters} + * with SELECT and ORDER BY clauses removed. + * + * @param queryParameters -the query parameters. + * @return the subselect fetch query fragment. + */ + public static String createSubselectFetchQueryFragment(QueryParameters queryParameters) { //TODO: ugly here: final String queryString = queryParameters.getFilteredSQL(); final int fromIndex = getFromIndex( queryString ); final int orderByIndex = queryString.lastIndexOf( "order by" ); - this.queryString = orderByIndex > 0 + final String subselectQueryFragment = orderByIndex > 0 ? queryString.substring( fromIndex, orderByIndex ) : queryString.substring( fromIndex ); if ( LOG.isTraceEnabled() ) { - LOG.tracef( "Generated SubselectFetch query: %s", queryString ); + LOG.tracef( "SubselectFetch query fragment: %s", subselectQueryFragment ); } + return subselectQueryFragment; } private static int getFromIndex(String queryString) { diff --git a/hibernate-core/src/main/java/org/hibernate/loader/Loader.java b/hibernate-core/src/main/java/org/hibernate/loader/Loader.java index a5953be1cf..d95978412b 100644 --- a/hibernate-core/src/main/java/org/hibernate/loader/Loader.java +++ b/hibernate-core/src/main/java/org/hibernate/loader/Loader.java @@ -1036,6 +1036,7 @@ private void createSubselects(List keys, QueryParameters queryParameters, Sessio final Loadable[] loadables = getEntityPersisters(); final String[] aliases = getAliases(); + final String subselectQueryString = SubselectFetch.createSubselectFetchQueryFragment( queryParameters ); for ( Object key : keys ) { final EntityKey[] rowKeys = (EntityKey[]) key; for ( int i = 0; i < rowKeys.length; i++ ) { @@ -1043,7 +1044,7 @@ private void createSubselects(List keys, QueryParameters queryParameters, Sessio if ( rowKeys[i] != null && loadables[i].hasSubselectLoadableCollections() ) { SubselectFetch subselectFetch = new SubselectFetch( - //getSQLString(), + subselectQueryString, aliases[i], loadables[i], queryParameters, diff --git a/hibernate-core/src/main/java/org/hibernate/loader/plan/exec/process/internal/ResultSetProcessingContextImpl.java b/hibernate-core/src/main/java/org/hibernate/loader/plan/exec/process/internal/ResultSetProcessingContextImpl.java index 1ec0acd7b3..8396533d65 100644 --- a/hibernate-core/src/main/java/org/hibernate/loader/plan/exec/process/internal/ResultSetProcessingContextImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/loader/plan/exec/process/internal/ResultSetProcessingContextImpl.java @@ -322,13 +322,14 @@ private void createSubselects() { final Map namedParameterLocMap = ResultSetProcessorHelper.buildNamedParameterLocMap( queryParameters, namedParameterContext ); + final String subselectQueryString = SubselectFetch.createSubselectFetchQueryFragment( queryParameters ); for ( Map.Entry> entry : subselectLoadableEntityKeyMap.entrySet() ) { if ( ! entry.getKey().hasSubselectLoadableCollections() ) { continue; } SubselectFetch subselectFetch = new SubselectFetch( - //getSQLString(), + subselectQueryString, null, // aliases[i], (Loadable) entry.getKey(), queryParameters, @@ -339,7 +340,6 @@ private void createSubselects() { for ( EntityKey key : entry.getValue() ) { session.getPersistenceContext().getBatchFetchQueue().addSubselect( key, subselectFetch ); } - } }