Hibernate Criteria

The Hibernate query by criteria (QBC) API lets you build a query by manipulating criteria objects at runtime. This approach lets you specify constraints dynamically without direct string manipulations, but it doesn’t lose much of the flexibility or power of HQL. On the other hand, queries expressed as criteria are often less readable than queries expressed in HQL.

To obtain a Criteria instance, call createCriteria(), passing the class of the objects you want the query to return. This is also called the root entity of the criteria query, the Employee in this example:

Criteria crit = session.createCriteria(Employee.class);

The Criteria instance may be used in the same way as a Query object, but it’s also used to construct the object-oriented representation of the query by adding Criterion instances and navigating associations to new Criterias.

Paging the result

Pagination is a commonly used technique. Users might see the result of their search request (for example, for specific Employees) as a page. This page shows only a limited subset (say, 10 Employees) at a time, and users can navigate to the next and previous pages manually. Both the Query and Criteria interfaces support this pagination of the query result:

Criteria crit = session.createCriteria(Employee.class);
crit.addOrder( Order.asc("firstName") );
crit.setFirstResult(40);
crit.setMaxResults(10);
List results = crit.list();

Starting from the fortieth object, we retrieve the next 10 objects. Note that there is no standard way to express pagination in SQL, but Hibernate knows the tricks to make this work efficiently on your particular database.

You can use the method-chaining coding style (methods return the receiving object instead of void) with both the Query and Criteria interfaces, rewriting the two previous examples as follows:

List results =
session.createCriteria(Employee.class)
 .addOrder( Order.asc("firstName") )
 .setFirstResult(40)
 .setMaxResults(10)

Restriction

Usually, you don’t want to retrieve all instances of a class. You must be able to express constraints on the property values of objects returned by the query. Doing so is called restriction. The where clause is used to express a restriction in both SQL and HQL; these expressions may be of arbitrary complexity.

For a criteria query, we must construct a Criterion object to express the constraint. The Expression class provides factory methods for built-in Criterion types.

Let’s create the same query using criteria and immediately execute it:

Criterion firstNameEq = Expression.eq("firstName", "Puneet");
Criteria crit = session.createCriteria(Employee.class);
crit.add(firstNameEq);
Employee employee = (Employee) crit.uniqueResult();

We create a Criterion holding the simple Expression for an equality comparison and add it to the Criteria. The uniqueResult() method executes the query and returns exactly one object as a result. Usually, we would write this a bit less verbosely, using method chaining:

Employee employee = (Employee) session.createCriteria(Employee.class)
    .add( Expression.eq("firstName", "Puneet") )
    .uniqueResult();

Comparison operators

The where clause is a logical expression that evaluates to true, false, or null for each tuple of objects.

In the case of criteria queries, all the same operators are available via the Expression class:

session.createCriteria(Employee.class)
    .add( Expression.between("salary",
    new Integer(200000),
    new Integer (499999))
).list();

String matching

The like operator allows wildcard searches, where the wildcard symbols are % and _, just as in SQL:

For criteria queries, wildcard searches may use either the same wildcard symbols or specify a MatchMode. Hibernate provides the MatchMode as part of the Criteria query API; we use it for writing string match expressions without string manipulation.

These two queries are equivalent:

session.createCriteria(Employee.class)
    .add( Expression.like("firstName", "P%") )
    .list();
session.createCriteria(Employee.class)
    .add( Expression.like("firstName ", "P", MatchMode.START) )
    .list();

The allowed MatchModes are START, END, ANYWHERE, and EXACT.

The Criteria API doesn’t currently support SQL function calls. It does, however, provide a special facility for case-insensitive searching:

session.createCriteria(Employee.class)
    .add( Expression.eq("firstName", "Puneet").ignoreCase() )
    .list();

Logical operators

Logical operators (and parentheses for grouping) are used to combine expressions:

If you add multiple Criterion instances to the one Criteria instance, they’re applied conjunctively (that is, using and):

session.createCriteria(Employee.class)
    .add( Expression.like("firstName", "P%") )
    .add( Expression.like("lastName", "A%") )

If you need disjunction (or), you have two options.

The first is to use Expression.or() together with Expression.and():

String[] emails = { "puneet@kruders.com<script type="text/javascript">
/* <![CDATA[ */
(function(){try{var s,a,i,j,r,c,l=document.getElementById("__cf_email__");a=l.className;if(a){s='';r=parseInt(a.substr(0,2),16);for(j=2;a.length-j;j+=2){c=parseInt(a.substr(j,2),16)^r;s+=String.fromCharCode(c);}s=document.createTextNode(s);l.parentNode.replaceChild(s,l);}}catch(e){}})();
/* ]]> */
</script>", "contact@kruders.com<script type="text/javascript">
/* <![CDATA[ */
(function(){try{var s,a,i,j,r,c,l=document.getElementById("__cf_email__");a=l.className;if(a){s='';r=parseInt(a.substr(0,2),16);for(j=2;a.length-j;j+=2){c=parseInt(a.substr(j,2),16)^r;s+=String.fromCharCode(c);}s=document.createTextNode(s);l.parentNode.replaceChild(s,l);}}catch(e){}})();
/* ]]> */
</script>" };
Criteria crit = session.createCriteria(Employee.class)
    .add(
    Expression.or(
    Expression.and(
    Expression.like("firstName", "P%"),
    Expression.like("lastName", "A%")
    ),
    Expression.in("email", emails)
    )
);

The second option is to use Expression.disjunction() together with Expression.conjunction():

String[] emails = { "puneet@kruders.com<script type="text/javascript">
/* <![CDATA[ */
(function(){try{var s,a,i,j,r,c,l=document.getElementById("__cf_email__");a=l.className;if(a){s='';r=parseInt(a.substr(0,2),16);for(j=2;a.length-j;j+=2){c=parseInt(a.substr(j,2),16)^r;s+=String.fromCharCode(c);}s=document.createTextNode(s);l.parentNode.replaceChild(s,l);}}catch(e){}})();
/* ]]> */
</script>", "contact@kruders.com<script type="text/javascript">
/* <![CDATA[ */
(function(){try{var s,a,i,j,r,c,l=document.getElementById("__cf_email__");a=l.className;if(a){s='';r=parseInt(a.substr(0,2),16);for(j=2;a.length-j;j+=2){c=parseInt(a.substr(j,2),16)^r;s+=String.fromCharCode(c);}s=document.createTextNode(s);l.parentNode.replaceChild(s,l);}}catch(e){}})();
/* ]]> */
</script>" };
Criteria crit = session.createCriteria(Employee.class)
    .add( Expression.disjunction()
    .add( Expression.conjunction()
    .add( Expression.like("firstName", "G%") )
    .add( Expression.like("lastName", "A%") )
    )
    .add( Expression.in("email", emails) )
);

Ordering query results

All query languages provide a mechanism for ordering query results. HQL. The Criteria API provides a similar facility:

List results = session.createCriteria(Employee.class)
    .addOrder( Order.asc("lastName") )
    .addOrder( Order.asc("firstName") )
    .list();

Projection and Aggregation

The Criteria API provides the org.hibernate.criterion.Projections class which can be used to get average, maximum or minimum of the property values. The Projections class is similar to the Restrictions class in that it provides several static factory methods for obtaining Projection instances. Following are the few examples covering different scenarios and can be used as per requirement:

Criteria cr = session.createCriteria(Employee.class);
 
// To get maximum salary.
cr.setProjection(Projections.max("salary"));
 
// To get minimum salary.
cr.setProjection(Projections.min("salary"));

Sql Script for Sample Code given below

Use the following Sql Script for creating table.

create table EMPLOYEE (
   EMPLOYEE_ID INT NOT NULL auto_increment,
   firstname VARCHAR(20) default NULL,
   lastname  VARCHAR(20) default NULL,
   salary     INT  default NULL,
   PRIMARY KEY (EMPLOYEE_ID)
);
You can download the source code of this example here.

One Response to Hibernate Criteria