What is Criteria api?

Criteria api in Hibernate is used to fetch data from database tables.
Though Hibernate Query Language can also be used to perform the same task but using queries makes maintenance difficult since the queries need to be written in string format while using Criteria involves classes and their properties.

It should be noted that Criteria can only be used to fetch data(or SELECT operations) and not for data manipulation tasks such as Insert, Update or Delete.

With Criteria api, you can
1. Fetch all records from a table(all columns and rows).
2. Fetch only selected columns.
3. Fetch records matching some condition(such as a website with name ‘codippa’)
4. Apply sorting on the records while fetching.
5. Apply JOINS for fetching records from multiple tables.
This post will guide you through the method of creating a criteria and use it to fetch records.

Database table and Entity

Before proceeding with learning about criteria, let us define the database table and the corresponding entity class.
Following is the structure of database table and sample records that will be referred throughout the examples.

idnameageeidsalary
1abc22e00120000
2def25e00230000
3ghi27e00340000

Entity class corresponding to the above database table is given below

import java.io.Serializable;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToOne;
import javax.persistence.Table;


@Entity
@Table(name = "employee")
public class Student implements Serializable {
   @Id
   @GeneratedValue(strategy=GenerationType.IDENTITY)
   @Column(name = "id")
   private int id;

   @Column(name = "name")
   private String empName;

   @Column(name = "age")
   private int age;

   @Column(name="eid")
   private String employeeId;

   public int getId() {
    return id;
   }

   public void setId(int id) {
    this.id = id;
   }

   public String getEmpName() {
    return empName;
   }

   public void setEmpName(String name) {
    this.empName = name;
   }

   public int getAge() {
    return age;
   }

   public void setAge(int age) {
    this.age = age;
   }
      
   public String getEmployeeId() {
    return employeeId;
   }
   
   public void setEmployeeId(String eid) { 
     this.employeeId = eid; 
   }

}

Hibernate configuration file that we will be using is given below

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">

<hibernate-configuration>
   <session-factory>
      <property name="connection.driver_class">com.mysql.jdbc.Driver</property>
      <property name="dialect">org.hibernate.dialect.MySQLDialect</property>
      <property name="hibernate.connection.url">
                               jdbc:mysql://localhost:3306/assessment</property>
      <property name="connection.username">root</property>
      <property name="connection.password">root</property>
      <property name="show_sql">true</property>
      <property name="hbm2ddl.auto">update</property>
   </session-factory>
</hibernate-configuration>

Place it inside src folder of your eclipse project.

Using Criteria api

To start using Criteria api, the first step is getting a Criteria object which belongs to org.hibernate package. This object will be used to leverage the features of Criteria classes.

An org.hibernate.Criteria object is retrieved by using createCriteria method on a org.hibernate.Session object.
This method takes the name of the class(or entity) on which you want the criteria methods to be applied. Following sections will clarify the various uses that a criteria object can be put to.

org.hibernate.Criteria is an interface. When its object is created, it is of type org.hibernae.internal.CriteriaImpl class.

Fetching all records

A criteria object can be used to fetch all records from a table. By all records, we mean complete rows and columns of the database table corresponding to the entity for which the criteria object is created.
Example,

import java.util.List;
import org.hibernate.Criteria;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.boot.registry.StandardServiceRegistry;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.cfg.Configuration;

public class CriteriaDemo {
   public static void main(String[] args) {
     // load configuration
     Configuration configuration = new Configuration().configure();
     //add classes to be read
     configuration.addAnnotatedClass(Employee.class);
     // create session factory
     StandardServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder()
      .applySettings(configuration.getProperties()).build();
     SessionFactory sessionFactory = configuration.buildSessionFactory(serviceRegistry);
     // create a session
     Session session = sessionFactory.openSession();
    
     // create criteria for Employee class
     Criteria criteria = session.createCriteria(Employee.class);
     // get all employee records.
     List list = criteria.list();
     // iterate over records
     for (Employee employee : list) {
       System.out.println("Employee name: " + employee.getName() +
                        ", id: " + employee.getEmployeeId());
     }
     session.close();
     sessionFactory.close();
   }
}

First we create a session object using the method that might be already known to you and then call createCriteria method supplying it Employee class. This returns a criteria object.

In order to fetch all records, list method of criteria is called which returns a java.util.List. This list contains all the records of employee table in the form of Employee objects.

When above code is executed, following query is printed at the console.

 

Hibernate: select this_.id as id1_0_0_, this_.name as name2_0_0_, this_.age as age3_0_0_, this_.eid as eid4_0_0_ from Employee this_

The output is

Employee name: abc, id: e001
Employee name: def, id: e002
Employee name: ghi, id: e003

Ordering records

Criteria api lets you sort the fetched records on the basis of the values of a column in ascending or descending order.
In other words, it lets you apply ORDER BY clause of an SQL query. This is done using criteria’s addOrder method which takes an org.hibernate.criterion.Order object.
This class has asc and desc methods which allow the result set to be arranged in ascending or descending order respectively.
These methods accept a String argument which is the property name on which sorting is performed. Example,

/* Session creation code */
// create criteria for Employee class
Criteria criteria = session.createCriteria(Employee.class);
// sort criteria result on id property in descending order
criteria.addOrder(Order.desc("id"))
// get all employee records.
List list = criteria.list();
// iterate over records
for (Employee employee : list) {
   System.out.println("Employee name: " + employee.getName() +
                       ", id: " + employee.getEmployeeId());
}

The output shows that the result set is sorted in the order of descending id values.

Employee name: ghi, id: e003
Employee name: def, id: e002
Employee name: abc, id: e001

SQL query executed by Hibernate printed at the console is given below. Notice an order by clause at the end.

Hibernate: select this_.id as id1_0_0_, this_.name as name2_0_0_, this_.age as age3_0_0_, this_.eid as eid4_0_0_ from Employee this_ order by this_.id desc

Fetching single column

Above examples fetched whole records from the database table but what if you want a single or some specific columns as the result.
Hibernate provides Projections and Projection classes to achieve this. Both these classes belong to org.hibernate.criterion package.

Projections class has a static method property which accepts the name of the property which should be included in the result set and returns a Projection object.
This object can then be added to the criteria using its setProjection method which accepts a Projection object as argument. Example is given below.
Note that list method now returns a list of String values containing names of employees and not Employee objects.

/* Session creation code */
// create criteria for Employee class
Criteria criteria = session.createCriteria(Employee.class);
// create a projection to fetch only name column
Projection p = Projections.property("name");
// add projection to criteria
criteria.setProjection(p); 
// get all employee names
List list = criteria.list();
// iterate over records
for (String employeeName : list) {
  System.out.println("Employee name: " + employeeName);
}

Output of execution of the code produces the following output

abc
def
ghi

Query printed at the console shows that only name column is fetched

Hibernate: select this_.name as y0_ from Employee this_

Fetching multiple columns

Above method only allows you to fetch a single column as the result since you can only associate only one projection to the criteria object.
But that does not mean that you can not fetch more than one columns.

It is possible using a ProjectionList which again belongs to the org.hibernate.criterion package. A ProjectionList is created by calling projectionList method of Projections class.
For each property/column to be fetched a projection is created and each projection is added to the ProjectionList by calling its add method.

Call add method for each property which needs to be included in the result set.
Finally link this ProjectionList to the criteria object by calling its setProjection method with ProjectionList as argument.

  /* Session creation code */

  Criteria criteria = session.createCriteria(Employee.class);
  // create a projection list
  ProjectionList projectionList = Projections.projectionList();
  // create a projection for fetching "name" property value
  Projection nameProjection = Projections.property("name");
  // add it to list
  projectionList.add(nameProjection);
  // create a projection for fetching "employeeId" property value
  Projection ageProjection = Projections.property("employeeId");
  // add it to list
  projectionList.add(ageProjection);
  // associate projection list to criteria
  criteria.setProjection(projectionList);
  // get all employee records
  List<Object[]> list = criteria.list();
  // iterate over records
  for (Object[] employeeData : list) {
     System.out.println("Employee name: " + employeeData[0] +
                    ", id: " + employeeData[1]);
  }

Note that list method of criteria returns a List of Object array in this case where each item in the list is an array of columns fetched or the projections created.

 

Employee name: ghi, id: e003
Employee name: def, id: e002
Employee name: abc, id: e001

Fetching records based on condition

Till now we dealt with fetching all records from a table(all or selective columns) but often it is required to fetch only records which match certain condition such as fetching only those employees whose age is greater than 25, fetching student with roll number 5, fetching all movies released between years 2015-2019 etc.

In normal SQL, this can be done by applying a WHERE clause but in Hibernate, criteria api lets you achieve this too using Restrictions class from org.hibernate.criterion package.
This class has static methods such as

MethodDescriptionSQL equivalent
eqTakes name of the property and a value. Those records whose property matches the given value are fetchedSame as applying = operator in SQL WHERE clause
inTakes name of property and an array of values. Records whose property name has values from among array are fetched Same as IN operator in SQL WHERE clause
betweenTakes name of property and two values. Records whose property value lies between the supplied values are fetchedSame as BETWEEN operator in SQL WHERE clause
isNullTakes name of property. Records whose values for the supplied property are null are fetchedSame as IS NULL expression in WHERE clause
isNotNullTakes name of property. Records whose values for the supplied property are non-null are fetchedSame as IS NOT NULL expression in WHERE clause
ilikeTakes name of the property and a value. Those records whose property contains the supplied value are fetched. Value comparison is case-insensitiveSame as LIKE operator in SQL WHERE clause

The restriction is added to the criteria object using its add method. Results fetched using criteria are as per the restriction applied. Below example fetches and employee whose id is e001.

/* Session creation code */

Criteria criteria = session.createCriteria(Employee.class);
// add condition to criteria object
criteria.add(Restrictions.eq("employeeId", "e001"));
// fetch employee with id "e001"
Employee employee = (Employee)criteria.uniqueResult();
System.out.println("Employee name: "+employee.getEmployeeName());

Note that since there will be only one result after applying the restriction, hence criteria’s uniqueResult method is used. If there are chances of multiple records, then list method should be used as before.

All methods of Restrictions class return a criterion object, which can be supplied to add method of criteria object. Also, it is possible to add multiple restrictions to a criteria object.

Query executed by Hibernate is

Hibernate: select this_.id as id1_0_0_, this_.name as name2_0_0_, this_.age as age3_0_0_, this_.eid as eid4_0_0_ from Employee this_ where this_.eid=?

Note the where clause added in the query.

That’s it about criteria api in this post.