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 14f035cea6..586875aff8 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 @@ -48,30 +48,92 @@ 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 - ) { + 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, + final Set resultingEntityKeys, + final Map namedParameterLocMap) { this.resultingEntityKeys = resultingEntityKeys; this.queryParameters = queryParameters; this.namedParameterLocMap = namedParameterLocMap; 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(); int fromIndex = queryString.indexOf(" from "); int orderByIndex = queryString.lastIndexOf("order by"); - this.queryString = orderByIndex>0 ? - queryString.substring(fromIndex, orderByIndex) : - queryString.substring(fromIndex); + 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; } public QueryParameters getQueryParameters() { 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 05ccd144b7..2a5d244c60 100644 --- a/hibernate-core/src/main/java/org/hibernate/loader/Loader.java +++ b/hibernate-core/src/main/java/org/hibernate/loader/Loader.java @@ -63,7 +63,6 @@ import org.hibernate.dialect.pagination.NoopLimitHandler; import org.hibernate.engine.internal.CacheHelper; import org.hibernate.engine.internal.TwoPhaseLoad; import org.hibernate.engine.jdbc.ColumnNameCache; -import org.hibernate.engine.jdbc.spi.ResultSetWrapper; import org.hibernate.engine.spi.EntityEntry; import org.hibernate.engine.spi.EntityKey; import org.hibernate.engine.spi.EntityUniqueKey; @@ -1014,6 +1013,9 @@ public abstract class Loader { final Loadable[] loadables = getEntityPersisters(); final String[] aliases = getAliases(); + final String subselectQueryString = SubselectFetch.createSubselectFetchQueryFragment( + queryParameters + ); final Iterator iter = keys.iterator(); while ( iter.hasNext() ) { @@ -1023,7 +1025,7 @@ public abstract class Loader { if ( rowKeys[i]!=null && loadables[i].hasSubselectLoadableCollections() ) { SubselectFetch subselectFetch = new SubselectFetch( - //getSQLString(), + subselectQueryString, aliases[i], loadables[i], queryParameters,