How to Select POJOs with a CriteriaQuery

Share this article

How to Select POJOs with a CriteriaQuery

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.

Frequently Asked Questions (FAQs) about Selecting POJOs with a CriteriaQuery

What is the purpose of using CriteriaQuery in Java?

CriteriaQuery is a type of query mechanism in Java that allows you to construct complex database queries using an object-oriented API, rather than hard-coding query strings. This approach provides a more flexible and dynamic way to build queries, making it easier to adapt your code to changing requirements. It also helps to prevent SQL injection attacks, as the query structure is defined programmatically rather than through string manipulation.

How do I create a CriteriaQuery instance?

To create a CriteriaQuery instance, you first need to obtain a CriteriaBuilder instance from the EntityManager. The CriteriaBuilder interface serves as a factory for all criteria queries. Here’s a simple example:

CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<YourEntity> cq = cb.createQuery(YourEntity.class);

How can I select specific columns using CriteriaQuery?

To select specific columns in a CriteriaQuery, you can use the multiselect() method of the CriteriaBuilder interface. This method takes a variable number of Selection arguments and returns a CompoundSelection instance. Here’s an example:

CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Tuple> cq = cb.createTupleQuery();
Root<YourEntity> root = cq.from(YourEntity.class);
cq.multiselect(root.get("column1"), root.get("column2"));

How can I add conditions to my CriteriaQuery?

You can add conditions to your CriteriaQuery using the where() method of the CriteriaQuery interface. This method takes a Predicate instance, which you can create using the various predicate methods of the CriteriaBuilder interface. Here’s an example:

CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<YourEntity> cq = cb.createQuery(YourEntity.class);
Root<YourEntity> root = cq.from(YourEntity.class);
cq.where(cb.equal(root.get("column1"), "value1"));

How can I order the results of my CriteriaQuery?

You can order the results of your CriteriaQuery using the orderBy() method of the CriteriaQuery interface. This method takes a variable number of Order instances, which you can create using the asc() and desc() methods of the CriteriaBuilder interface. Here’s an example:

CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<YourEntity> cq = cb.createQuery(YourEntity.class);
Root<YourEntity> root = cq.from(YourEntity.class);
cq.orderBy(cb.asc(root.get("column1")));

How can I execute my CriteriaQuery?

You can execute your CriteriaQuery using the createQuery() method of the EntityManager interface. This method takes a CriteriaQuery instance and returns a TypedQuery instance, which you can then execute using the getResultList() or getSingleResult() method. Here’s an example:

CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<YourEntity> cq = cb.createQuery(YourEntity.class);
Root<YourEntity> root = cq.from(YourEntity.class);
TypedQuery<YourEntity> query = em.createQuery(cq);
List<YourEntity> results = query.getResultList();

How can I join tables using CriteriaQuery?

You can join tables using the join() method of the Root or Join interface. This method takes the name of the attribute representing the relationship to the other entity. Here’s an example:

CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<YourEntity> cq = cb.createQuery(YourEntity.class);
Root<YourEntity> root = cq.from(YourEntity.class);
Join<YourEntity, OtherEntity> join = root.join("otherEntity");

How can I group results using CriteriaQuery?

You can group results using the groupBy() method of the CriteriaQuery interface. This method takes a variable number of Expression instances, which you can create using the get() method of the Root or Path interface. Here’s an example:

CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<YourEntity> cq = cb.createQuery(YourEntity.class);
Root<YourEntity> root = cq.from(YourEntity.class);
cq.groupBy(root.get("column1"));

How can I use aggregate functions with CriteriaQuery?

You can use aggregate functions like count, sum, avg, min, and max with CriteriaQuery using the corresponding methods of the CriteriaBuilder interface. Here’s an example:

CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Long> cq = cb.createQuery(Long.class);
Root<YourEntity> root = cq.from(YourEntity.class);
cq.select(cb.count(root));

How can I handle exceptions when using CriteriaQuery?

When using CriteriaQuery, exceptions can be handled using a try-catch block. The most common exception you might encounter is the PersistenceException, which is a runtime exception that wraps all failures that occur within the persistence mechanism. Here’s an example:

try {
// Your CriteriaQuery code here
} catch (PersistenceException e) {
// Handle exception here
}

Thorben JanssenThorben Janssen
View Author

Thorben Janssen is an independent trainer with more than 15 years of experience with Hibernate. You can find more of his posts and several free cheat sheets about JPA and Hibernate on his blog or you can take his free video course about finding and fixing n+1 select issues.

HibernateJPAnicolaipquick-tip
Share this article
Read Next
Get the freshest news and resources for developers, designers and digital creators in your inbox each week