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.
id | name | age | eid | salary |
---|---|---|---|---|
1 | abc | 22 | e001 | 20000 |
2 | def | 25 | e002 | 30000 |
3 | ghi | 27 | e003 | 40000 |
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
Method | Description | SQL equivalent |
---|---|---|
eq | Takes name of the property and a value. Those records whose property matches the given value are fetched | Same as applying = operator in SQL WHERE clause |
in | Takes 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 |
between | Takes name of property and two values. Records whose property value lies between the supplied values are fetched | Same as BETWEEN operator in SQL WHERE clause |
isNull | Takes name of property. Records whose values for the supplied property are null are fetched | Same as IS NULL expression in WHERE clause |
isNotNull | Takes name of property. Records whose values for the supplied property are non-null are fetched | Same as IS NOT NULL expression in WHERE clause |
ilike | Takes name of the property and a value. Those records whose property contains the supplied value are fetched. Value comparison is case-insensitive | Same 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.
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.