Java
Article
By Thorben Janssen

How to Select POJOs with a CriteriaQuery

By Thorben Janssen

The Criteria API provides a type-safe way to define queries programmatically. Similar to JPQL, you can use it to select a set of entity attributes and map each result set record to a Plain Old Java Object (POJO).

The Criteria API supports the same feature set as JPQL, and I show in my new book Hibernate Tips – More than 70 solutions to common Hibernate problems how you can use it to implement a variety of use cases. It’s a Hibernate cookbook with more than 70 ready-to-use recipes for topics like basic and advanced mappings, logging, Java 8 support, caching and statically and dynamically defined queries. You can get it this week on Amazon at a special launch price of just $2.99.

Let’s take a look at one of the recipes included in the book. It uses the Criteria API to programmatically define a query that selects a set of database columns and returns them as POJOs. To get the most out of this post, you should already be familiar with Hibernate’s basic concepts.


How to select POJOs with a CriteriaQuery

Problem

JPQL supports constructor expressions to select POJOs instead of entities or scalar values. Can I do the same with the Criteria API?

Solution

You can use a similar constructor expression with the Criteria API as you use in JPQL queries. In the following example, I want to select AuthorValue objects.

public class AuthorValue {

   private String firstName;
   private String lastName;

   public AuthorValue(String firstName, String lastName) {
       this.firstName = firstName;
       this.lastName = lastName;
   }

   ...
}

The definition of the CriteriaQuery follows the same approach as you use to select entities.

You first need to get a CriteriaBuilder instance from the EntityManager. It’s a factory class that helps you to define different parts of your query, like bind parameters, function calls, and predicates.

You then create a CriteriaQuery instance that is the root of the object graph that represents your query. I recommend providing the return type of your query as a parameter to the createQuery method. It creates a typed instance of the CriteriaQuery interface. I want to select AuthorValue objects in this example and, therefore, provide AuthorValue.class as the parameter.

In the next step, you define the FROM clause of the query. In this example, I use the Author entity as the root of the query.

Then you can define the projection of your query. In this example, it’s a call of the AuthorValue constructor. The construct method of the CriteriaBuilder allows you to define constructor calls. Call this method using the class that Hibernate instantiates as the first parameter and an optional list of Selections that are used as constructor parameters.

In this example, I use the JPA Metamodel class Author_ to reference the firstName and lastName attributes of the Author entity. If you’re not familiar with the JPA Metamodel, take a look at the Hibernate tip How to reference entity attributes in a type-safe way, which provides a comfortable and type-safe way to reference entity attributes.

The definition of the WHERE clause is optional. If you want to select all records from the database, you can skip this block and execute your query. That’s what I do in this example. You can see an example of a WHERE clause definition in the How to select entities with a CriteriaQuery chapter.

CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<AuthorValue> q = cb.createQuery(AuthorValue.class);
Root<Author> root = q.from(Author.class);
q.select(
   cb.construct(
       AuthorValue.class,
       root.get(Author_.firstName),
       root.get(Author_.lastName)));

That’s all you need to do to define the CriteriaQuery. You can now execute it in two steps. You first need to call the createQuery method of the EntityManager with your CriteriaQuery. This method call returns the same TypedQuery interface as you use in your JPQL queries. You can use it to set bind parameter values or to paginate the query result. I don’t use any bind parameters in this example and therefore, can skip this part. In the final step, you need to call the getResultList method on the TypedQuery interface to execute the query and retrieve a List of AuthorValue objects.

TypedQuery<AuthorValue> query = em.createQuery(q);
List<AuthorValue> authors = query.getResultList();

When I created the query, I referenced the firstName and lastName attributes in the constructor call definition. As you can see in the following log messages, Hibernate used these reference to generates an SQL query that selects the firstName and lastName columns from the Author table.

13:43:09,884 DEBUG [org.hibernate.SQL] -
   select
       author0_.firstName as col_0_0_,
       author0_.lastName as col_1_0_
   from
       Author author0_

Source Code

You can find a download link for a project with executable test cases for this Hibernate tip in the book.

Learn More

If you don’t want to create a POJO to represent your query result, you can also select a set of scalar values. I show you how to do that in the chapter How to select multiple scalar values in a CriteriaQuery.

And if you want to use the Criteria API in your project, you should also have a look at the JPA metamodel. It provides a great way to create queries in a type-safe way. I show you how to use and generate the required classes in the chapter How to reference entity attributes in a type-safe way.


Using the CriteriaQuery easily gets you POJOs from Hibernate

Summary

The Criteria API provides a type-safe option to define queries programmatically. As you have seen in the book excerpt, you can use it to select a set of database columns and let Hibernate map each result set record to a POJO.

Get more recipes like this in my new book Hibernate Tips: More than 70 solutions to common Hibernate problems. It gives you more than 70 ready-to-use recipes for topics like basic and advanced mappings, logging, Java 8 support, caching and statically and dynamically defined queries. For just a few days, you can get the ebook for $2.99 and the paperback for $12.99.

Recommended
Sponsors
Get the latest in Java, once a week, for free.