Hi everybody,
attached I have sketched an idea for providing support of dynamic
result set mappings. This is neither a fully-fledged proposal nor
final, but rather meant as food for thought with respect to the
forthcoming concall.
It suggests that from the entity manager a result mapping builder may
be retrieved.
ResultMappingBuilder getResultMappingBuilder();
This builder produces a result mapping, which then may be used to
create a query object from the native sql query string by
Query createNativeQuery(String sqlString, ResultMapping resultMapping);
or perhaps by something like
TypedQuery<Tuple> createNativeQuery(String sqlString,
ResultMapping resultMapping);
In the latter case one would have to think of how to get hold of the
corresponding tuple elements or of using aliases.
The result mapping builder serves two purposes. It both provides the
other builders required to create the entity, field and constructor
mappings and builds the final result mapping. Since column mappings are
that simple no dedicated builder is provisioned, rather they may be
obtained directly from the result mapping builder.
The entity, field, columns and constructor mappings directly correspond
to the respective annotations @EntityResult, @FieldResult,
@ColumnResult and @ConstructorResult. There is only one deviation
regarding the handling of embedded ids, embeddables and relations with
compound primary key on the target side by field mappings. Rather than
using the dot notation within the name string as with @FieldResult,
field mappings of the sub fields are collected taking advantage of the
respective singular attributes.
You will find the interfaces in attached drsm_entwurf.jar in subpackage
javax.persistence.dynamicrsm along with a dummy EntityManager used for
compilation. I neither do propose to have a subpackage of its own nor
the name used, it just helped me to keep my environment clean when
playing around with it.
The file drsm_tests.jar contains the examples from section 3.8.16 of
the JPA 2.1 expert group draft 2 (as listed below) along with some
dummy classes needed for compilation. The attached picture illustrates
the interface hierarchy.
Now the examples :
ResultMappingBuilder rmb = entityManager.getResultMappingBuilder();
EntityMappingBuilder<Order> emb =
rmb.getEntityMappingBuilder(Order.class);
ResultMapping resultMapping = rmb.add(emb.build())
.build();
@SqlResultSetMapping(name="WidgetOrderResults",
entities=_at_EntityResult(entityClass=com.acme.Order.class))
(page 133, first example)
ResultMappingBuilder rmb = entityManager.getResultMappingBuilder();
EntityMappingBuilder<Order> embO =
rmb.getEntityMappingBuilder(Order.class);
EntityMappingBuilder<Item> embI =
rmb.getEntityMappingBuilder(Item.class);
ResultMapping resultMapping = rmb.add(embO.build())
.add(embI.build())
.build();
@SqlResultSetMapping(name="OrderItemResults",
entities={
@EntityResult(entityClass=com.acme.Order.class),
@EntityResult(entityClass=com.acme.Item.class) })
(page 133, second example)
ResultMappingBuilder rmb = entityManager.getResultMappingBuilder();
EntityMappingBuilder<Order> embO =
rmb.getEntityMappingBuilder(Order.class);
FieldMappingBuilder<Order, Integer> mapId =
rmb.getFieldMappingBuilder(Order_.id);
FieldMappingBuilder<Order, Integer> mapQuantity =
rmb.getFieldMappingBuilder(Order_.quantity);
FieldMappingBuilder<Order, Item> mapItem =
rmb.getFieldMappingBuilder(Order_.item);
EntityMappingBuilder<Item> embI =
rmb.getEntityMappingBuilder(Item.class);
ResultMapping resultMapping =
rmb.add(embO.add(mapId.column("order_id"))
.add(mapQuantity.column("order_quantity"))
.add(mapItem.column("order_item"))
.build()
)
.add(embI.build())
.build();
@SqlResultSetMapping(name="OrderItemResults",
entities={
@EntityResult(entityClass=com.acme.Order.class,
fields={
@FieldResult(name="id",
column="order_id"),
@FieldResult(name="quantity",
column="order_quantity"),
@FieldResult(name="item",
column="order_item")}),
@EntityResult(entityClass=com.acme.Item.class) })
(page 134)
ResultMappingBuilder rmb = entityManager.getResultMappingBuilder();
EntityMappingBuilder<Customer> emb =
rmb.getEntityMappingBuilder(Customer.class);
FieldMappingBuilder<Customer, Integer> mapId =
rmb.getFieldMappingBuilder(Customer_.id);
FieldMappingBuilder<Customer, Address> mapAddress =
rmb.getFieldMappingBuilder(Customer_.address);
FieldMappingBuilder<Customer, String> mapStatus =
rmb.getFieldMappingBuilder(Customer_.status);
FieldMappingBuilder<Address, String> mapStreet =
rmb.getFieldMappingBuilder(Address_.street);
FieldMappingBuilder<Address, String> mapCity =
rmb.getFieldMappingBuilder(Address_.city);
FieldMappingBuilder<Address, String> mapState =
rmb.getFieldMappingBuilder(Address_.state);
ResultMapping resultMapping =
rmb.add(emb.add(mapId.column("customer_id"))
.add(mapAddress.add(
mapStreet.column("customer_street"))
.add(
mapCity.column("customer_city"))
.add(
mapState.column("customer_state"))
.build()
)
.add(mapStatus.column("customer_status"))
.build()
)
.build();
@SqlResultSetMapping(name="CustomerResults",
entities={
@EntityResult(entityClass=com.acme.Customer.class,
fields={
@FieldResult(name="id",
column="customer_id"),
@FieldResult(name="address.street",
column="customer_street"),
@FieldResult(name="address.city",
column="customer_city"),
@FieldResult(name="address.state",
column="customer_state"),
@FieldResult(name="status",
column="customer_status")})
})
(page 135, first example)
ResultMappingBuilder rmb = entityManager.getResultMappingBuilder();
EntityMappingBuilder<Order> embO =
rmb.getEntityMappingBuilder(Order.class);
FieldMappingBuilder<Order, Integer> mapId =
rmb.getFieldMappingBuilder(Order_.id);
FieldMappingBuilder<Order, Integer> mapQuantity =
rmb.getFieldMappingBuilder(Order_.quantity);
FieldMappingBuilder<Order, Item> mapItem =
rmb.getFieldMappingBuilder(Order_.item);
FieldMappingBuilder<Item, Integer> mapItemId =
rmb.getFieldMappingBuilder(Item_.id);
FieldMappingBuilder<Item, String> mapItemName =
rmb.getFieldMappingBuilder(Item_.name);
EntityMappingBuilder<Item> embI =
rmb.getEntityMappingBuilder(Item.class);
ResultMapping resultMapping =
rmb.add(embO.add(mapId.column("order_id"))
.add(mapQuantity.column("order_quantity"))
.add(mapItem.add(
mapItemId.column("order_item_id"))
.add(
mapItemName.column("order_item_name"))
.build()
)
.build()
)
.add(embI.build())
.build();
@SqlResultSetMapping(name="OrderItemResults",
entities={
@EntityResult(entityClass=com.acme.Order.class,
fields={
@FieldResult(name="id",
column="order_id"),
@FieldResult(name="quantity",
column="order_quantity"),
@FieldResult(name="item.id",
column="order_item_id")}),
@FieldResult(name="item.name",
column="order_item_name")}),
@EntityResult(entityClass=com.acme.Item.class) })
(page 135, second example)
ResultMappingBuilder rmb = entityManager.getResultMappingBuilder();
EntityMappingBuilder<Order> embO =
rmb.getEntityMappingBuilder(Order.class);
FieldMappingBuilder<Order, Integer> mapId =
rmb.getFieldMappingBuilder(Order_.id);
FieldMappingBuilder<Order, Integer> mapQuantity =
rmb.getFieldMappingBuilder(Order_.quantity);
FieldMappingBuilder<Order, Item> mapItem =
rmb.getFieldMappingBuilder(Order_.item);
FieldMappingBuilder<Item, ItemPk> mapItemPk =
rmb.getFieldMappingBuilder(Item_.itemPk);
FieldMappingBuilder<ItemPk, Integer> mapItemPkId =
rmb.getFieldMappingBuilder(ItemPk_.id);
FieldMappingBuilder<ItemPk, String> mapItemPkName =
rmb.getFieldMappingBuilder(ItemPk_.name);
EntityMappingBuilder<Item> embI =
rmb.getEntityMappingBuilder(Item.class);
ResultMapping resultMapping =
rmb.add(embO.add(mapId.column("order_id"))
.add(mapQuantity.column("order_quantity"))
.add(mapItem.add(
mapItemPk.add(
mapItemPkId.column("order_item_id"))
.add(
mapItemPkName.column("order_item_name"))
.build()
)
.build()
)
.build()
)
.add(embI.build())
.build();
@SqlResultSetMapping(name="OrderItemResults",
entities={
@EntityResult(entityClass=com.acme.Order.class,
fields={
@FieldResult(name="id",
column="order_id"),
@FieldResult(name="quantity",
column="order_quantity"),
@FieldResult(name="item.itemPk.id",
column="order_item_id")}),
@FieldResult(name="item.itemPk.name",
column="order_item_name")}),
@EntityResult(entityClass=com.acme.Item.class) })
(page 136)
ResultMappingBuilder rmb = entityManager.getResultMappingBuilder();
ConstructorMappingBuilder<CustomerDetails> cmb =
rmb.getConstructorMappingBuilder(CustomerDetails.class);
ResultMapping resultMapping =
rmb.add(cmb.add(rmb.getColumnMapping("id"))
.add(rmb.getColumnMapping("name"))
.add(rmb.getColumnMapping("orderCount"))
.add(rmb.getColumnMapping("averageOrder",
Double.class))
.build()
)
.build();
@SqlResultSetMapping(name="CustomerDetailsResult",
classes={
@ConstructorResult(targetClass=com.acme.CustomerDetails.class,
columns={ @ColumnResult(name="id"),
@ColumnResult(name="name"),
@ColumnResult(name="orderCount"),
@ColumnResult(name="avgOrder",
type=Double.class)})
})
(page 137, second example)
ResultMappingBuilder rmb = entityManager.getResultMappingBuilder();
EntityMappingBuilder<Order> emb =
rmb.getEntityMappingBuilder(Order.class);
FieldMappingBuilder<Order, Integer> mapId =
rmb.getFieldMappingBuilder(Order_.id);
FieldMappingBuilder<Order, Integer> mapQuantity =
rmb.getFieldMappingBuilder(Order_.quantity);
FieldMappingBuilder<Order, Item> mapItem =
rmb.getFieldMappingBuilder(Order_.item);
ResultMapping resultMapping =
rmb.add(emb.add(mapId.column("order_id"))
.add(mapQuantity.column("order_quantity"))
.add(mapItem.column("order_item"))
.build()
)
.add(rmb.getColumnMapping("item_name"))
.add(rmb.getColumnMapping("item_shipdate",
java.util.Date.class))
.build();
@SqlResultSetMapping(name="OrderResults",
entities={
@EntityResult(entityClass=com.acme.Order.class,
fields={
@FieldResult(name="id",
column="order_id"),
@FieldResult(name="quantity",
column="order_quantity"),
@FieldResult(name="item",
column="order_item")})},
columns={ @ColumnResult(name="item_name"),
@ColumnResult(name="item_shipdate",
type=java.util.Date.class)}
)
(page 137, first example)
Thank you very much for your time
Rainer
---
Rainer Schweigkoffer SAP AG Walldorf
Business Solution & Technology TD Core JS&I
Technology Development Dietmar-Hopp-Allee 16
Java Server Core D-69190 Walldorf
JEE Implementation Group phone: +49 6227 7 45305
Building 3, I.3.14 fax: +49 6227 7 821177
rainer.schweigkoffer_at_sap.com
Sitz der Gesellschaft/Registered Office: Walldorf, Germany
Vorstand/SAP Executive Board: Werner Brandt, Angelika Dammann,
Bill McDermott (Co-CEO), Gerhard Oswald, Vishal Sikka,
Jim Hagemann Snabe (Co-CEO)
Vorsitzender des Aufsichtsrats/Chairperson of the SAP Supervisory
Board: Hasso Plattner
Registergericht/Commercial Register Mannheim No HRB 350269
Diese E-Mail kann Betriebs- oder Geschaeftsgeheimnisse oder sonstige
vertrauliche Informationen enthalten. Sollten Sie diese E-Mail
irrtuemlich erhalten haben, ist Ihnen eine Verwertung des Inhalts,
eine Vervielfaeltigung oder Weitergabe der E-Mail ausdruecklich
untersagt. Bitte benachrichtigen Sie uns und vernichten Sie die
empfangene E-Mail. Vielen Dank.
This e-mail may contain trade secrets or privileged, undisclosed, or
otherwise confidential information. If you have received this e-mail
in error, you are hereby notified that any review, copying, or
distribution of it is strictly prohibited. Please inform us
immediately and destroy the original transmittal. Thank you for your
cooperation.
Der folgende Teil dieser Nachricht enthält einen Anhang im
sogenannten Internet MIME Nachrichtenformat.
Wenn Sie Pegasus Mail oder ein beliebiges anderes MIME-kompatibles
Email-System verwenden, sollte Sie den Anhang mit Ihrem Email-System
speichern oder anzeigen können. Anderenfalls fragen Sie Ihren Administrator.
The following section of this message contains a file attachment
prepared for transmission using the Internet MIME message format.
If you are using Pegasus Mail, or any another MIME-compliant system,
you should be able to save it or view it from within your mailer.
If you cannot, please ask your system administrator for assistance.
---- Datei Information/File information -----------
Datei/File: drsm_entwurf.jar
Datum/Date: 15 Jun 2011, 14:11
Größe/Size: 5194 bytes.
Typ/Type: ZIP-archive
Der folgende Teil dieser Nachricht enthält einen Anhang im
sogenannten Internet MIME Nachrichtenformat.
Wenn Sie Pegasus Mail oder ein beliebiges anderes MIME-kompatibles
Email-System verwenden, sollte Sie den Anhang mit Ihrem Email-System
speichern oder anzeigen können. Anderenfalls fragen Sie Ihren Administrator.
The following section of this message contains a file attachment
prepared for transmission using the Internet MIME message format.
If you are using Pegasus Mail, or any another MIME-compliant system,
you should be able to save it or view it from within your mailer.
If you cannot, please ask your system administrator for assistance.
---- Datei Information/File information -----------
Datei/File: JPA2.1_ResultMapping.jpg
Datum/Date: 15 Jun 2011, 14:12
Größe/Size: 138056 bytes.
Typ/Type: JPEG-image
Der folgende Teil dieser Nachricht enthält einen Anhang im
sogenannten Internet MIME Nachrichtenformat.
Wenn Sie Pegasus Mail oder ein beliebiges anderes MIME-kompatibles
Email-System verwenden, sollte Sie den Anhang mit Ihrem Email-System
speichern oder anzeigen können. Anderenfalls fragen Sie Ihren Administrator.
The following section of this message contains a file attachment
prepared for transmission using the Internet MIME message format.
If you are using Pegasus Mail, or any another MIME-compliant system,
you should be able to save it or view it from within your mailer.
If you cannot, please ask your system administrator for assistance.
---- Datei Information/File information -----------
Datei/File: drsm_tests.jar
Datum/Date: 15 Jun 2011, 14:11
Größe/Size: 8234 bytes.
Typ/Type: ZIP-archive