[hibernate-dev] 6.0 - ResultTransformer
Steve Ebersole
steve at hibernate.org
Tue Sep 13 20:50:57 EDT 2016
BTW... https://hibernate.atlassian.net/browse/HHH-11104
On Tue, Sep 13, 2016 at 7: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.
>>>>
>>>
More information about the hibernate-dev
mailing list