Programmatic Criteria Queries using JPA Criteria API
Tags: jpa, java, hibernate, all
Published: 2020-09-15 22:43:23

---
title: Programmatic Criteria Queries using JPA Criteria API
published: true
tags: jpa, java, hibernate ,all
canonical_url: http://www.initgrep.com/posts/java/jpa/create-programmatic-queries-using-criteria-api
---

Java Persistence API (JPA) provides the specification of managing data, such as accessing and persisting data, between Java Objects and the databases.

There are obviously many ways in JPA that could be used to interact with a database such as JPQL(Java Persistence Query Language), Criteria API, and Entity specific methods such as persist, merge, remove, flush, etc.

I initially found Criteria API quite intimidating. To be frank, I had to invest quite some time to figure it out. It eventually turned out to be quite a fluent API. I thought why not just write about the experiences. So here it is, **“Creating Programmatic Criteria Queries using JPA Criteria API”**.

Criteria Queries are type-safe and portable. They are written using Java programming language APIs. They use the abstract schema of the persistent entities to find, modify, and delete persistent entities by invoking JPA Entity Operations.

 

We will be using the following domain model for building the criteria queries in this tutorial.

![Object Model- UML](http://www.initgrep.com/assets/images/Criteria-object-UML.png)_<ins>UML diagram describing the Object Relationship Mapping</ins>_

We have three Objects( ref. to diagram above ) `Student` , `Course` and `Passport`. Each of the Objects has a relationship with each other:

- `Student` has a `One-To-One` relationship with `Passport`. It means that Each Student can only have one Passport and vice versa.
- `Student` has a `One-To-Many` relationship with `Address` which means that a student can have one or more addresses and an address is always assigned to one student.
- `Student` has a `Many-To-Many` relationship with `Course` which means that Each Student can enroll in many courses and one course can have many students enrolled.

 

We will begin with a simple Criteria Query and slowly try to build upon it.

```
public Long getStudentsCount() {
            
        / **CriteriaBuilder instance** / 
        CriteriaBuilder builder = entityManager.getCriteriaBuilder();
        
        / **create a criteriaQuery Object** /
        CriteriaQuery<Long> studentQuery = builder.createQuery(Long.class);
        
        / **create a Root Object -> references to the queried entity** /
        Root<Student> studentRoot = studentQuery.from(Student.class);
        
        / **Path Object to refer the attribute name of entity** /
        / **we are not using it for now** /
        Path<Object> namePath = studentRoot.get("name");
        
        / **Aggregate Expression for count operation** /
        Expression<Long> countExpression = builder.count(studentRoot);
        
        / **** /
        studentQuery.select(countExpression);
        
        /** instance of Typed Query */
        TypedQuery<Long> typedStudentQuery = 
                            entityManager.createQuery(studentQuery);
        
        / **return the result** /
        Long count = typedStudentQuery.getSingleResult();
        
        return count;
    }
```

_The above code example retrieves the total count of students present in the database._

Criteria queries are an Object graph where each part of the graph represents an atomic part of the query. The various steps in building the object graph roughly translate to the following steps.

- A `CriteriaBuilder` interface contains all the required methods to build Criteria Queries, Expressions, Ordering, and Predicates.
- `CriteriaQuery` interface defines functionality required to build a top-level query. The type specified for criteria query i.e `criteriaQuery<Class<T> resultClass>` would be the type of the result returned. If no type is provided, the type of result would be `Object`. Criteria Query contains the methods that specify the item(s) to be returned in the query result, restrict the result based on certain conditions, group results, specify an order for the result, and [much more](https://docs.oracle.com/javaee/6/api/javax/persistence/criteria/CriteriaQuery.html).
- `Root` interface represents the root entities involved in the query. There could be multiple roots defined in the Criteria Query.
- `Path` interface represents the path to the attribute in the `root` entity. `Path` interface also `extends` to the `Expression` Interface which contains methods that return Predicates.
- `builder.count()` is an aggregate method. It returns an expression that would be used for `Selection` of the result. When aggregate methods are used as arguments in the `select` method, the type of the query should match the return type of aggregate method.
- A `TypedQuery` instance is required to run the `CriteriaQuery`.

The final output of the above example is below :)

```
select
        count(student0_.id) as col_0_0_ 
    from
        student student0_
```

**It seems quite the over work–doesn’t it.** The output of so many lines of code is just a plain old `SELECT` query. But the Criteria API was created to serve a different purpose i.e _programmable Query API_. It helps to build queries dynamically. You could write just one program to build queries for all objects in your application or build queries depending upon your business logic.

Let’s say, we want to get the count of either Students, Courses or any other entities present in our application. We could either write different queries for each of them or we could only use Criteria API.

```
public <T> Long getCountOfEntity(Class<T> claz) {
            
        CriteriaBuilder builder = em.getCriteriaBuilder();
        CriteriaQuery<Long> studentQuery = builder.createQuery(Long.class);
        Root<T> root = studentQuery.from(claz);
        Expression<Long> countExpression = builder.count(root);
        studentQuery.select(countExpression);
        TypedQuery<Long> typedStudentQuery = em.createQuery(studentQuery);
        
        return typedStudentQuery.getSingleResult();
    }
```

I have only updated the previous example to allow the generic parameter which specifies the `Class` of the `Entity`. The rest of the Code stays the same. You can learn more about Java Generics [here](https://docs.oracle.com/javase/tutorial/java/generics/index.html).

Let’s look at the above example in detail.

**Criteria Query**

```
CriteriaQuery<T> createQuery(Class<T> resultClass);
```

`CreateQuery` method takes the `Class` name of the result type as an argument.

- If the result is returned as a data-set related to the entity e.g all the students or one of the students. The parameter should be `Student.class`. 

```
builder.createQuery(Student.class);
```

- If the query returns any other result irrespective of which entity it works on, It should have a parameter of the returned type. As we saw above, when the count was returned, the parameter type was `Long.class`

```
builder.createQuery(Long.class);
```

**Root**

```
Root<T> root = studentQuery.from(Student.Class)
```

The `Root` refers to the entity on which the query would be run such as `Student.class` in the above example.

**Select**

```
studentQuery.select(countExpression);
```

The `select` method specifies the result to be returned by the Query. If all the attributes of an entity are supposed to be returned instead of just returning the count, we could pass the `root` entity as the parameter such as below.

```
studentQuery.select(studentRoot);
```
&nbsp;
 
_If you have come this far, you might also want to read about various methods, Criteria API provides to implement criteria join, Fetch Join, Aggregate functions, and subqueries. I have posted a detailed post about it. **[Click here](https://www.initgrep.com/posts/java/jpa/create-programmatic-queries-using-criteria-api)** to check it out._