[hibernate-dev] 6.0 - ResultTransformer

Steve Ebersole steve at hibernate.org
Tue Sep 13 20:05:06 EDT 2016


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.
>>>
>>


More information about the hibernate-dev mailing list