jsr338-experts@jpa-spec.java.net

[jsr338-experts] Re: improved SQL result set mapping

From: Emmanuel Bernard <emmanuel.bernard_at_jboss.com>
Date: Thu, 28 Apr 2011 06:58:19 -0400

An entirely different twist / solution to this problem could be to provide a customizable post processing step to transform the results returned by a query.
This could be considered an orthogonal feature though.

//JPA 2 API
interface ResultTransformer {
   public Object transformTuple(Object[] tuple, String[] aliasOrColumnName);
}

//user implementation
class ConstructorResultTransformer {
    private final Constructor constructor;

    public ConstructorResultTransformer(Constructor constructor) {
        this.constructor = constructor;
    }

    public Object transformTuple(Object[] tuple, String[] aliasesOrColumnNames) {
        //TODO try catch for *Exception
        return constructor.newInstance( tuple );
    }
}

This is not limited to constructors, one can think of many use cases like:
 - returning maps
 - setting values based on setters rather than constructors

This is not a fleshed out proposal, a few areas need to be worked out, including:
 - how is aliasesOrColumnNames exactly defined
 - how to make it so it plays well in the type system of a TypedQuery

Emmanuel

On 14 avr. 2011, at 02:16, Linda DeMichiel wrote:

> Another pending item in the query area is the ability to use
> constructors for non-entity results of native queries.
>
> Here's another strawman proposal to get the discussion started:
>
>
> To support the use of constructors in SqlResultSetMapping, we could
> define a ConstructorResult mapping:
>
> @Target(value={})
> @Retention(value=RUNTIME)
> public @interface ConstructorResult {
> Class targetClass();
> ColumnResult columns();
> }
>
>
> This could be used in combination with @EntityResult and @ColumnResult
> in SQLResultSetMapping:
>
> @Target({TYPE})
> @Retention(RUNTIME)
> public @interface SqlResultSetMapping {
>
> /**
> * The name given to the result set mapping, and used to refer
> * to it in the methods of the Query API.
> */
> String name();
>
> /** Specifies the result set mapping to entities. */
> EntityResult[] entities() default {};
>
> /** Specifies the result set mapping to constructors. */
> ConstructorResult[] classes() default {};
>
> /** Specifies the result set mapping to scalar values. */
> ColumnResult[] columns() default {};
> }
>
>
> We should also be more specific about the relationship among the
> shape of the SELECT list, the specified SqlResultSetMapping, and the
> order in which results are returned by the execution of the query.
> This is currently undefined in the spec.
>
> For example:
>
> When a SqlResultSetMapping specifies more than one mapping type (i.e.,
> more than one of EntityResult, ConstructorResult, ColumnResult), then
> for each row in the SQL result, the query execution will result in an
> Object[] whose elements are as follows, in order: any entity results
> (in the order in which they are defined in the entities element); any
> instances of classes corresponding to constructor results (in the
> order defined in the classes element); and any instances corresponding
> to column results (in the order defined in the columns element).
>
> Another issue is that when a column is not mapped as an entity
> attribute, there is currently no way to specify the type to be returned
> by the query (e.g., Timestamp instead of Date).
>
> I suggest that we address this by adding another element to
> @ColumnResult, e.g., type, which would default to void.class for
> default JDBC type mapping.
>
>
> Feedback, please!
>
> thanks,
>
> -Linda
>