persistence icon indicating copy to clipboard operation
persistence copied to clipboard

programmatic result set mappings for native queries

Open lukasj opened this issue 13 years ago • 7 comments

API for specifying result type mappings. Currently this is handled through metadata, and is therefore static

lukasj avatar Dec 05 '11 22:12 lukasj

  • Issue Imported From: https://github.com/javaee/jpa-spec/issues/9
  • Original Issue Raised By:@glassfishrobot
  • Original Issue Assigned To: @ldemichiel

lukasj avatar Aug 31 '18 16:08 lukasj

@glassfishrobot Commented Reported by @ldemichiel

lukasj avatar Dec 05 '11 22:12 lukasj

@glassfishrobot Commented This issue was imported from java.net JIRA JPA_SPEC-9

lukasj avatar May 05 '17 06:05 lukasj

Even though this is issue #9, from 2011, it's actually been quite near the top of my priority list for quite a long time.

We absolutely need an API-based way to define SQL result set mappings!

gavinking avatar Aug 10 '23 22:08 gavinking

How about something like this:

Result.Entity<Order> orderResultMapping = 
        Result.entity(Order.class, 
                Result.field(Order_.id "order_id"),
                Result.field(Order_.quantity, "order_quantity"),
                Result.field(Order_.item, "order_item")
       );
Query<Order> query = entityManager.createNativeQuery("...",  orderResultMapping);

The class Result would have interfaces Entity<T>, Constructor<T>, Field<T>, and Column<T> with the same members as @EntityResult, @ConstructorResult, @FieldResult, and @ColumnResult. And it would have matching constructor methods entity(), constructor(), field(), and column().

There would also be:

  • a super interface Result.Typed<T> extended by these inner interfaces,
  • a Result.Compound extending Result.Typed<Object[]>, and perhaps even
  • a Result.Tuple extending Result.Typed<Tuple>.

Now, with use of static imports, the above code would simplify to:

Entity<Order> orderResultMapping = 
        entity(Order.class, 
                field(Order_.id "order_id"),
                field(Order_.quantity, "order_quantity"),
                field(Order_.item, "order_item")
       );
Query<Order> query = entityManager.createNativeQuery("...", orderResultMapping);

Hell, we could even in principle have Result.Entity<T> implement the annotation type EntityResult, Result.Field<T> implement the annotation type FieldResult, etc, which would mean that implementations would have almost no work to do.

gavinking avatar Aug 19 '23 10:08 gavinking

On Twitter the idea of using string templates was suggested by Gunnar Morling.

I believe it would be possible to make something like this work:

NativeQuery query = 
        NATIVE."select o.id as \{Order_.id}, o.quantity as \{Order_.quantity}, o.item as \{Order_.item} from orders o";
Query<Order> query = entityManager.createNativeQuery(query);

Of course, something quite a bit more complicated would be needed to handle multiple instances of the same entity in the result set, embeddables, etc. And ultimately this would probably end up needing some sort of "dynamic" result set mapping API.

Now, I know that looks like a completely different feature to the one proposed in the issue description, but my intuition is that this is actually a better solution to the most common use cases for a result set mapping API.

Anyway, the point is that we should keep this application in mind in the design of a result set mapping API.

gavinking avatar Aug 20 '23 16:08 gavinking