[hibernate-dev] 6.0 - ResultTransformer

Gail Badner gbadner at redhat.com
Tue Sep 13 22:55:38 EDT 2016


Sorry for the late response. I've been looking through the fix for HHH-5163
[1] to jog my memory.

Here are some reasons why CacheableResultTransformer is important when
caching query results:

1) The same SQL can be generated when associations are joined as when
associations are fetched, but what gets cached is different. The cached
results exclude fetched associations. QueryKey needs to contain the proper
CacheableResultTransformer to indicate which tuple elements are cached to
distinguish the differing results.

2) IIRC, the tuple elements that got cached by the legacy Criteria and HQL
were inconsistent, and I believe that in some cases the ResultTransformer
was applied before caching the value, which added to problems assembling
the query results (HHH--2463). CacheableResultTransformer ensured that what
got cached was consistent (excluding fetched values), and ensured that rows
were untransformed (padded with nulls where fetches were) and
re-transformed (if necessary) by a specified transformer as necessary.

I added lots of tests for this change, so I think we will find out quickly
if something gets broken.

Steve, I'm not completely following your discussion. Some pseudocode would
help.

Let me know if you need more details.

[1]
https://github.com/hibernate/hibernate-orm/commit/dc00c4dcde1bae399a9350bd4a13f9a2a449f6c3

On Tue, Sep 13, 2016 at 5:05 PM, Steve Ebersole <steve at hibernate.org> wrote:

> Hmmm there is an interesting aspect to Tuple + TupleTransformer.. both
> expect to get the root selection aliases and would naturally expect those
> to match in length to the values to transform.  Basically only one can
> "consume" the aliases.
>
> I think that because Tuple is a "higher precedence" (it defines the result
> type) it ought to win that battle.  But then that is inconsistent for
> TupleTransformer.  IMO either we let Tuple consume the aliases or we
> disallow this combo.
>
> On Tue, Sep 13, 2016 at 6:00 PM Steve Ebersole <steve at hibernate.org>
> wrote:
>
> > So here is the path I am following initially.. It is straightforward to
> > explain to a user which I like.
> >
> > In terms of processing each "row" in a result there is the RowTransformer
> > contract I mentioned earlier, or maybe I mentioned on HipChat.  I added
> the
> > capability for RowTransformer to be nested, specifically I defined 2
> > levels:
> >
> >    1. an implicit RowTransformer.  This is resolved based on the
> >    following chart:
> >       1. If there is a resultType and it is Object[].class we do a "pass
> >       thru"
> >       2. If there is a resultType and it is Tuple.class we do use a
> >       RowTransformer adapter that builds a Tuple
> >       3. If there is just one selection we transform the Object[] by
> >       returning just row[0]
> >    2. a RowTransformer adapter for TupleTransformer, if specified
> >
> > And just a word on dynamic-instantiation here.. it is actually done prior
> > to any of this.  In fact, in 6.0 a dynamic-instantiation is no different
> > that other selectable expressions.
> >
> >
> >
> > On Tue, Sep 13, 2016 at 9:19 AM Steve Ebersole <steve at hibernate.org>
> > wrote:
> >
> >> So again, this all boils down to the interplay with
> >> (Result|Tuple|ResultList)Transformer, dynamic instantiations, and
> >> result-types.
> >>
> >> So let's look at some specific cases...
> >>
> >> First some cases I think are perfectly valid:
> >>
> >> session.createQuery( "select new map(...) ...", Map.class ) - returns a
> >> List<Map<String,?>>
> >> session.createQuery( "select new list(...) ...", List.class ) - returns
> a
> >> List<List> (rather than List<Object[]>)
> >> session.createQuery( "select new DTO(...), DTO.class ) - returns a
> >> List<DTO>
> >>
> >> Ok, so I cheated there by not including transformers :)  So let's look
> at
> >> adding transformers into this mix[1].
> >>
> >> session.createQuery( "select new map(...) ...", Map.class )
> >>         .setTupleTransformer( new TupleTranformer<SomeNonMap>() {...} )
> >>
> >> this one is illegal.  It defines the Query resultType as Map, but the
> >> applied TupleTranformer is transforming those to SomeNonMap -> CCE.
> >> This should be either:
> >>
> >> session.createQuery( "select new map(...) ...", SomeNonMap.class )
> >>         .setTupleTransformer( new TupleTranformer<SomeNonMap>() {...} )
> >>
> >> or (non-typed):
> >>
> >> session.createQuery( "select new map(...) ..." )
> >>         .setTupleTransformer( new TupleTranformer<SomeNonMap>() {...} )
> >>
> >> In both of those cases, the TupleTranformer is handed a Object[] where
> >> the only element is the Map.
> >>
> >> I guess too that defines the blueprint for what is and what is not
> >> supported and how the various pieces apply.
> >>
> >>
> >> But I am still not sure about the semantic wrt TupleTransformer and/or
> >> dynamic-instantiation in combination with Tuple.  I kind of think those
> >> should just be illegal combos:
> >>
> >> session.createQuery( "select ...", Tuple.class )
> >>         .setTupleTransformer( () -> ... )
> >>
> >> Unless the TupleTransformer is building a Tuple, I that is a bad combo
> >> for sure.
> >>
> >> I thik dynamic-instantiation and TupleTransformer is ok:
> >>
> >> session.createQuery( "select new DTO(...) ..." )
> >>         .setTupleTransformer( () -> ... )
> >>
> >> Here the TupleTransformer would get Object[] with the long element being
> >> the DTO; the "query result" is whatever the TupleTransformer returns.
> >>
> >> Any other specific combos we should clarify?
> >>
> >>
> >>
> >> [1]  I am using the new TupleTransformer and ResultListTransformer
> >> breakdowns I have defined on 6.0 :
> >> https://gist.github.com/sebersole/bc721caa20a5e4a97cbde44567b0b2ea
> >>
> >>
> >>
> >> On Tue, Sep 13, 2016 at 8:52 AM Steve Ebersole <steve at hibernate.org>
> >> wrote:
> >>
> >>> On Tue, Sep 13, 2016 at 2:26 AM Gunnar Morling <gunnar at hibernate.org>
> >>> wrote:
> >>>
> >>>> > Between dynamic-instantiation, Tuple-handling...
> >>>>
> >>>> To be sure, WDYM by "tuple-handling"?
> >>>>
> >>>
> >>> javax.persistence.Tuple
> >>>
> >>> So I gave just one example earlier of how all of these things do not
> >>> necessarily fit together in inherently obvious ways.  Some combinations
> >>> I think are ok; others are not.  In sitting here and trying to describe
> >>> this to a user from a documentation perspective, it is not a simple
> >>> explanation.
> >>>
> >>> I'll follow up with a separate reply that covers those combos for
> >>> discussion.
> >>>
> >>>
> >>> One use case for result transformers are full-text searches executed
> >>>> through Hibernate Search's Session extension FullTextSession (see
> [1]).
> >>>>
> >>>> For full-text searches we don't use HQL/JPQL, so the "new ..." syntax
> >>>> cannot be used, but I don't know about tuple-handling.
> >>>>
> >>>
> >>> Well for sure you do not allow the user to use HQL/JPQL.  But I'd have
> >>> to assume that under the covers you handle resolving that FullTextQuery
> >>> yourself from the indexes - which means this is not even a ORM Query
> at all
> >>> and what we do with ResultTransformer in ORM in regards to Query is
> >>> completely irrelevant for you.  In other words I would have to think
> that
> >>> Search itself is applying that ResultTransformer in your example, not
> ORM.
> >>> Very different.
> >>>
> >>
> _______________________________________________
> hibernate-dev mailing list
> hibernate-dev at lists.jboss.org
> https://lists.jboss.org/mailman/listinfo/hibernate-dev
>


More information about the hibernate-dev mailing list