1. Overview
In this article we are going to discuss a very useful feature of Hibernate – the Criteria Queries.
It not only enables us to write queries without doing raw SQL, but also gives us some Object Oriented control over the queries, which is one of the main features of Hibernate.
The Criteria API allows us to build up a criteria query object programmatically, where we can apply different kind of filtration rules and logical conditions. And the Session provides the createCriteria() API – which can be used to create a Criteria object that returns instances of the persistence object’s class when we execute a query.
2. Maven Dependencies
In order to use Hibernate make sure you add the latest version of it to the dependencies section of your pom.xml file:
<dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-core</artifactId> <version>5.2.1.Final</version> </dependency>
The latest version of Hibernate can be found here.
3. Simple Example using Criteria
Now since we know what a criteria query is, we can start looking at how to retrieve data using them. Let’s have a look at how to get all the instances of a particular class from database.
Let’s start with a basic example.
We have an Item class which represents the tuple “ITEM” in the database:
public class Item implements Serializable { private Integer itemId; private String itemName; private String itemDescription; private Integer itemPrice; // standard setters and getters }
Let’s look at a simple criteria query which will retrieve all the rows of “ITEM” from the database:
Session session = HibernateUtil.getHibernateSession(); Criteria cr = session.createCriteria(Item.class); long startTimeCriteria = System.nanoTime(); cr.add(Restrictions.like("itemName", "%item One%")); List results = cr.list();
The above query is a simple demonstration of how to get all the items. Let’s see what was done, step by step:
- Create a session object of type Session
- Create an instance of Session from the SessionFactory object
- Create an instance of Criteria by calling the createCriteria() method
- Call the list() method of the criteria object which gives us the results
Now that we’ve covered the basics, let’s move on to some of the features of criteria query:
3.1. Using Restrictions
The add() method can be used with Criteria object to add restriction for a criteria query. For that we also need to use the Restriction class.
The following code snippet of code contains all the available functionalities available with Restriction class:
To get items having price more than 1000:
cr.add(Restrictions.gt("itemPrice", 1000));
To get items having itemPrice less than 1000:
cr.add(Restrictions.lt("itemPrice", 1000));
To get items having itemNames start with Chair:
cr.add(Restrictions.like("itemName", "chair%"));
Case sensitive form of the above restriction:
cr.add(Restrictions.ilike("itemName", "Chair%"));
To get records having itemPrice in between 100 and 200:
cr.add(Restrictions.between("itemPrice", 100, 200));
To check if the given property is null:
cr.add(Restrictions.isNull("itemDescription"));
To check if the given property is not null:
cr.add(Restrictions.isNotNull("itemDescription"));
You can also use the methods isEmpty() and isNotEmpty() to test if a List within a class is empty or not.
The above code shows all the operations that can be performed with the Criteria API.
Now inevitably the question comes, weather we can combine two or more of the above comparisons or not. The answer is of course yes – the Criteria API allows us to easily chain restrictions:
cr.add(Restrictions.isNotEmpty("itemDescription")) .add(Restrictions.like("itemName", "chair%"));
To add two restrictions with logical operations:
Criterion greaterThanPrice = Restrictions.gt("itemPrice", 1000); Criterion chairItems = Restrictions.like("itemName", "Chair%");
To get items with the above defined conditions joined with Logical OR:
LogicalExpression orExample = Restrictions.or(greaterThanPrice, chairItems); cr.add(orExample);
To get items matching with the above defined conditions joined with Logical AND:
LogicalExpression andExample = Restrictions.or(greaterThanPrice, chairItems); cr.add(andExample);
3.2. Sorting
Now that we know the basic usage of Criteria, let’s have a look at the sorting functionalities of Criteria.
In the following example we order the list in an ascending order of the name and then in a descending order of the price:
List sortedItems = cr.addOrder(Order.asc("itemName")) .addOrder(Order.desc("itemPrice")) .list();
In the next section we will have a look at how to do aggregate functions.
3.3. Projections, Aggregates And Grouping Functions
So far we have covered most of the basic topics. Now let’s have a look at the different aggregate functions:
Set projections:
List itemProjected = session.createCriteria(Item.class) .setProjection(Projections.rowCount()) .add( Restrictions.eq("itemPrice", 12000)) .list();
The following is an example of aggregate functions:
Aggregate function for Average:
List avgItemPriceList = session.createCriteria(Item.class) .setProjection(Projections.projectionList() .add(Projections.avg("itemPrice"))) .list();
Other useful aggregate methods that are available are sum(), max(), min() , count() etc.
4. Advantage Over HQL
In the previous sections we’ve covered how to use Criteria Queries.
Clearly, the main and most hard-hitting advantage of Criteria queries over HQL is the nice, clean, Object Oriented API.
We can simply write more flexible, dynamic queries compared to plain HQL. The logic can be refactored with the IDE and has all the type-safety benefits of the Java language itself.
There are of course some disadvantages as well, especially around more complex joins.
So, generally speaking, we’ll have to use the best tool for the job – that can be the Criteria API in most cases, but there are definitely cases were we’ll have to go lower level.
5. Conclusion
In this quick writeup we focused on the basics of Criteria Queries in Hibernate, and also on some of the advanced features of the API.
And of course the code discussed here is available in the Github repository.