JavaEnterprise JavaCriteria Queries in JPA 2.0 and Hibernate: The APIs Have It

Criteria Queries in JPA 2.0 and Hibernate: The APIs Have It

One of the main areas in which version 2.0 of the Java Persistence API (JPA) improved from the previous version is criteria queries. Not only was its query language enhanced, but JPA 2.0 also offers new APIs for criteria queries. The most helpful of these APIs, however, may be one that was introduced as part of another ORM solution, Hibernate 3.0.

Before the introduction of Hibernate’s criteria query API in version 3.0, both JPA and Hibernate offered very powerful object-oriented querying languages for performing queries on databases. JPA offered the Java Persistence Query Language (JPQL), while Hibernate offered the Hibernate Query Language (HQL). HQL queries are case insensitive except for Java classes and properties, and both languages use the string-based approach to define queries. However, the string-based approach has a major limitation: the syntax errors in the queries are not detected during compile time because the compiler checks only for strings.

The criteria query API overcomes this limitation by enabling the programmer to define queries through the construction of object-based query definitions. The criteria query API helps in creating structured and nested queries, provides compile time safety, and most importantly, never allows the programmer to build queries that have incorrect syntax.

In this article, we present a brief comparison of the criteria queries features in JPA 2 and Hibernate. In particular, we explore JPA 2’s Metamodel APIs for criteria queries, an innovative feature that is not available in Hibernate.

Criteria Queries in JPA 2

The Java Persistence Criteria API’s data model is based on the abstract persistence schema of entities, their embedded objects, and their relationships. The Java Persistence Criteria API is closely related to JPQL (a powerful feature that is largely responsible for the success of JPA) and designed in a way to allow similar invocations.

The simple criteria query shown below creates a criteria object for the Employee class and returns all the instances of Employee:

....@PersistenceContextEntityManager entityManager;CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();CriteriaQuery<Employee> cqEmp = criteriaBuilder.createQuery(Employee.class);Root<Employee> employee = cqEmp.from(Employee.class);cqEmp.select(employee);TypeQuery<Employee>  typeQuery = entityManager.createQuery(cqEmp);List<Employee> employees = typeQuery.getResultList();....

What happens in the code is first an object of CriteriaBuilder is created with EntityManager. A query object is created on the CriteriaBuilder with the CriteriaQuery interface. This query object is used to specify the attributes of the query. Then the root of the query is obtained from the query object. Next, the type of query (select, in this example) is specified on the query object. The query object created is prepared for execution by specifying the type of query result. Finally, the query is executed with the invocation of the getResultList() method, where the result type (a collection of employee entities) is stored in a List object.

The equivalent query in JPQL would be:

SELECT e FROM EMPLOYEE e

Metamodel in JPA 2

Java Persistence Criteria queries are based on a metamodel of the persistence unit’s managed classes. The abstract persistence schema is composed of metamodel objects over which the Criteria API operates. A metamodel class models the persistent state and relationships of the corresponding managed class, which is the advantage of criteria queries in JPA 2.

The JPA 2 specification details how to represent the meta information of a persistent entity in a metamodel class. If this is achieved strictly by an application, it is referred to as Canonical Metamodel. A canonical metamodel class is static if all the members of the class are static and public. However, if a developer creates metamodel classes on his/her own, they are considered Non Canonical Metamodel classes.

Let’s try to understand metamodel classes by using the same Employee example as in the previous section. The Employee entity class has three persistence fields: empId, empName and empUnit.

package com.empdetails;....@Entitypublic class Employee {@Idprotected String empId;protected String empName;protected String empUnit;...}

The corresponding metamodel class could be:

package com.empdetails;....@Static Metamodel(Employee.class)public class Employee_ {public static volatile SingularAttribute<Employee, String> empId;public static volatile SingularAttribute<Employee, String> empName;public static volatile SingularAttribute<Employee, String> empUnit;}

The metamodel can be used as follows:

@PersistenceContextEntityManager entityManager;CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();CriteriaQuery query = criteriaBuilder.createQuery(Employee.class);Root<Employee> emp = query.from(Employee.class);// Get the metamodel of Employee entityEntityType<Employee> Employee_ = emp.getModel();

The JPA 2 specification provides a set of interfaces for dynamically accessing the metamodel corresponding to the persistence unit’s managed classes. The javax.persistence.metamodel interfaces enable developers to access dynamically the metamodel of the persistent state and relationships of a persistence unit’s managed classes. The metamodel can be accessed through the EntityManagerFactory or EntityManager getMetaModel() methods. If the metamodel class has to be obtained first, then use this code:

@PersistenceContextEntityManager entityManager;Metamodel model = entityManager.getMetamodel();// Get the metamodel before the ROOTEntityType<Employee> Employee_ = model.entity(Employee.class);

Criteria Queries in Hibernate

In Hibernate, an org.hibernate.Criteria object represents a criteria query object, which is created using a Session object. The simple example below creates a criteria object for the Employee class and returns all the instances of Employee:

Criteria queryObj = session.createCriteria(Employee.class);List<Employee> empList = queryObj.list();

The HQL for the corresponding criteria query is shown below. This is generally generated by the Hibernate framework with some configuration settings in the XML file.

HQL: Hibernate: select this_.id as id1_0_, this_.fname as fname1_0_, this_.lname as lname1_0_ from employee this_

The query results can be narrowed down by applying certain restrictions as shown below:

List<Employee> emps=session.createCriteria(Employee.class).add (Restrictions.like("Lname", "s%")).add (Restrictions.between("id", 1, 2)).list();   HQL: select this_.id as id1_0_, this_.fname as fname1_0_, this_.lname as lname1_0_ from employee this_ where this_.lname like ? and this_.id between ? and ?

Every individual query criterion applied for a criteria query is a type of org.hibernate.criterion.Criterion and a factory of built-in criterion types is defined by the org.hibernate.criterion.Restrictions class. Logical operators can also be attached to criteria queries using the Restriction class like this:

List<Employee> employeeList = session.createCriteria(Employee.class)   .add (Restrictions.like("Lname", "K%"))   .add (Restrictions.and(Restrictions.eq("Id", new Integer(24)),Restrictions.isNotNull("Id"))).list();HQL: select this_.id as id1_0_, this_.fname as fname1_0_, this_.lname as lname1_0_ from employee this_ where this_.lname like ? and (this_.id=? and this_.id is not null)

The org.hibernate.criterion.Order class can be used to order the query results as shown here:

List<Employee> employeeList=  session.createCriteria(Employee.class)         .addOrder(Order.asc("Lname"))         .addOrder(Order.desc("Id")).setMaResults(50).list(); HQL: select this_.id as id1_0_, this_.fname as fname1_0_, this_.lname as lname1_0_ from employee this_ order by this_.lname asc, this_.id desc limit ?

Query by Example, a powerful feature introduced in Hibernate 3.0, allows a criteria query to be supplied with an example instance, which is set with properties that need to be retrieved. Here is an example:

Employee exampleObject = new Employee();exampleObject.setId(3);exampleObject.setFname("Nischith");exampleObject.setLname("K L");   List<Employee> resultEmp = session.createCriteria(Employee.class).add(Example.create(exampleObject)).list();HQL: select this_.id as id1_0_, this_.fname as fname1_0_, this_.lname as lname1_0_ from employee this_ where (this_.fname=? and this_.lname=?)

Conclusion

In this article we compared the features for criteria queries in JPA 2 with those available in Hibernate. In particular, we discussed the introduction of the Metamodel APIs for criteria queries in JPA 2, a differentiating feature from Hibernate.

Acknowledgements

The authors would like to sincerely thank Mr. Subrahmanya SV (VP, ECOM Research Group, E&R) for his ideas, guidance, support and constant encouragement and Ms. Mahalakshmi for kindly reviewing this article and providing valuable comments.

About the Authors

Sangeetha S. works as a Senior Technical Architect at the E-Commerce Research Labs at Infosys Technologies. She has over 10 years of experience in design and development of Java and Java EE applications. She has co-authored a book on ‘J2EE Architecture’ and also has written articles for online Java publications.

Nitin KL works at the E-Commerce Research Labs at Infosys Technologies. He is involved in design and development of Java EE applications using Hibernate, iBATIS, and JPA.

Get the Free Newsletter!
Subscribe to Developer Insider for top news, trends & analysis
This email address is invalid.
Get the Free Newsletter!
Subscribe to Developer Insider for top news, trends & analysis
This email address is invalid.

Latest Posts

Related Stories