In the first post of this series, we had a look at some mapping definition between the query result and one entity. The mapping definitions got more complex in the second part, as we mapped the query result to multiple entities and handled additional columns.

In this post, we will have a look at the Constructor Result Mappings introduced in JPA 2.1. This feature allows us to call the constructor of a value object with the result of the query, similar to the JPQL constructor expressions. This is often used, if we want to provide a specific view of our domain model to the client.

The example

Before we start, lets have a look at the entity model that we will use for the examples. If you read the second part of this series, you are already familiar with the Author and Book entities. Both entities are quite simple. The Author entity has an id, a version, a first name and a last name. The Book entity has an id, a version, a title and a reference to the Author. To avoid unnecessary complexity, each Book was written by only one Author.

As we want to map our query results to a value object, we need an additional class called BookValue with an id, a version, a title and the name of the author.

I used Wildfly 8.2 with Hibernate 4.3.7 to test the examples in this series. But as these are standard JPA features, you should be able to use them with all other JPA 2.1 implementations, e.g. with the GlassFish 4.1 application server which uses EclipseLink.
You can find the source code on my github account.

How to map to a value object

Selecting entities and returning a tree of objects to the caller is not always the best approach. The caller often needs only a subset of the provided information and a specific value object would be much more efficient. For these situations, JPQL supports constructor expressions that can be specified in the select part of the JPQL query and define the constructor call for each selected record.

The BookValue in our example could be used in a client to show some information about a Book and the name of the Author. As long as we only need the name of the Author, there is no need to select and transfer the whole Author entity. It is more efficient to use an object of BookValue and select the name of the Author in the query.
In the next step, we need to define a mapping that uses the query result to call the constructor of the BookValue. This is done similar to the mappings we created before with the @SqlResultSetMapping annotation. The mapping shown in the following code snippet consists of a name and a @ConstructorResult annotation.
The name of the mapping, BookValueMapping in this example, will later be used to tell the EntityManager which mapping to use. The @ConstructorResult annotation defines the constructor call for a given target class. This is the BookValue in our example. The array of @ColumnResult annotations defines the columns of the query result that will be used as constructor parameters with their type and order. The type attribute is optional and you only need to provide it, if the type of the column is different to the type of the constructor parameter. In this case, the default types of the id and version columns are BigInteger and need to be converted to Long.

And like all the mapping definitions before, also the constructor result mapping can be defined in a mapping XML file. The easiest way to do this is to use the default mapping file called orm.xml that will be automatically used, if it is added to the META-INF directory of the jar file.
The usage of the constructor mapping is identical to the other SQL result set mappings. We need to provide it to the createNativeQuery(String sqlString, String resultSetMapping) method of the EntityManager and we get a List.

First of all, whole tutorials are great about ResultSetMapping, thank you so much…

when I use your way, I am getting this kind of error and I didn’t figure it out. I have two entity classes (Projects.java and ProjectsFlow.java) like yours (Author.java and Book.java) and also I have a class for result mapping ProjectsTables.java like your BookValue.java…This is the error