Criteria in Hibernate

In Hibernate, Criteria API is a powerful and flexible mechanism to create database queries in an object-oriented fashion. Unlike HQL (Hibernate Query Language), which is string-based, Criteria API uses methods and objects to create queries, ensuring better readability and maintainability.
The Criteria API is used for dynamically building queries in a type-safe way without the need to write SQL or HQL. While the older Criteria API has been deprecated since Hibernate 5, the new CriteriaQuery API (JPA Criteria API) is the recommended way of handling complex queries.

1. Basic Structure of Criteria API

Let's start with the basics. The CriteriaBuilder is used to create CriteriaQuery objects. The query is then executed using EntityManager.

Basic Query Example:

// EntityManager and CriteriaBuilder are required for the Criteria API
EntityManager em = entityManagerFactory.createEntityManager();
CriteriaBuilder cb = em.getCriteriaBuilder();

// Create CriteriaQuery object for the Employee entity
CriteriaQuery<Employee> query = cb.createQuery(Employee.class);

// Define root of the query (i.e., from Employee)
Root<Employee> root = query.from(Employee.class);

// Select all employees
query.select(root);

// Execute the query and get the result list
List<Employee> employees = em.createQuery(query).getResultList();

Here, the Criteria API is used to fetch all Employee records from the database. Root represents the entity in the query, and CriteriaBuilder is used to construct the query.

2. Building Queries with Criteria API

a. Filtering (WHERE clause)

You can apply filtering conditions using the where() method. The CriteriaBuilder provides methods to create Predicate objects for conditions.

Example: Fetch employees with a specific salary:

// Create query
CriteriaQuery<Employee> query = cb.createQuery(Employee.class);

// Define root
Root<Employee> root = query.from(Employee.class);

// Create condition for salary greater than 50000
Predicate condition = cb.gt(root.get("salary"), 50000);

// Apply the condition to the query
query.select(root).where(condition);

// Execute the query
List<Employee> result = em.createQuery(query).getResultList();
b. Sorting (ORDER BY clause)

You can sort results by specifying the order using CriteriaBuilder and Order.

Example: Fetch employees ordered by salary in descending order:

CriteriaQuery<Employee> query = cb.createQuery(Employee.class);

// Define root
Root<Employee> root = query.from(Employee.class);

// Define ordering by salary in descending order
query.select(root).orderBy(cb.desc(root.get("salary")));

// Execute the query
List<Employee> result = em.createQuery(query).getResultList();
c. Pagination (LIMIT and OFFSET)

You can apply pagination using setFirstResult() and setMaxResults().

Example: Fetch employees with pagination:

TypedQuery<Employee> typedQuery = em.createQuery(query);
typedQuery.setFirstResult(10);  // Skip first 10 rows
typedQuery.setMaxResults(20);   // Fetch next 20 rows

List<Employee> paginatedEmployees = typedQuery.getResultList();
3. Inserting and Updating with Criteria API

The Criteria API is primarily used for select queries. However, Hibernate does not support direct insert and update operations via the Criteria API itself. These operations should be done using HQL, JPQL, or programmatically in Java.

a. Inserting Records (Programmatic Insertion)

To insert a record, you generally create a new entity instance and persist it:

EntityTransaction transaction = em.getTransaction();
transaction.begin();

// Create new Employee object
Employee newEmployee = new Employee();
newEmployee.setName("John Doe");
newEmployee.setSalary(60000);

// Persist the entity (insert into the database)
em.persist(newEmployee);

transaction.commit();

b. Updating Records

To update records, you can retrieve the entity, modify its fields, and merge it back into the database:

EntityTransaction transaction = em.getTransaction();
transaction.begin();

// Fetch the employee by ID
Employee employee = em.find(Employee.class, 1);

// Update the salary
employee.setSalary(70000);

// Merge the entity (update in the database)
em.merge(employee);

transaction.commit();

For bulk update or delete operations, you should use JPQL or HQL. Hibernate’s Criteria API does not support bulk updates.

4. Complex Queries with Criteria API

a. Join Queries

You can perform joins between entities using join() or joinFetch() methods.

Example: Fetch employees and their departments using JOIN:

CriteriaQuery<Tuple> query = cb.createTupleQuery();
Root<Employee> employeeRoot = query.from(Employee.class);

// Perform join on Employee and Department
Join<Employee, Department> departmentJoin = employeeRoot.join("department");

// Select employee name and department name
query.multiselect(employeeRoot.get("name"), departmentJoin.get("name"));

// Execute the query
List<Tuple> results = em.createQuery(query).getResultList();
for (Tuple tuple : results) {
    System.out.println("Employee: " + tuple.get(0) + ", Department: " + tuple.get(1));
}

b. Grouping (GROUP BY clause)

You can group the results using groupBy() method in Criteria API.

Example: Group employees by department and count them:

CriteriaQuery<Tuple> query = cb.createTupleQuery();
Root<Employee> employeeRoot = query.from(Employee.class);

// Join with Department
Join<Employee, Department> departmentJoin = employeeRoot.join("department");

// Group by department and count employees
query.multiselect(departmentJoin.get("name"), cb.count(employeeRoot.get("id")))
     .groupBy(departmentJoin.get("name"));

// Execute the query
List<Tuple> result = em.createQuery(query).getResultList();
for (Tuple tuple : result) {
    System.out.println("Department: " + tuple.get(0) + ", Employee Count: " + tuple.get(1));
}

c. Aggregations (COUNT, SUM, MAX, etc.)

You can perform aggregate functions such as COUNT(), SUM(), MAX(), etc., using CriteriaBuilder.

Example: Find the maximum salary of employees:

CriteriaQuery<Double> query = cb.createQuery(Double.class);
Root<Employee> employeeRoot = query.from(Employee.class);

// Find maximum salary
query.select(cb.max(employeeRoot.get("salary")));

// Execute the query
Double maxSalary = em.createQuery(query).getSingleResult();
System.out.println("Maximum Salary: " + maxSalary);

Conclusion

  • The Criteria API in Hibernate is excellent for building type-safe, dynamic, and flexible queries.
  • Although you can select, filter, sort, paginate, and perform complex queries like joins and groupings, it’s important to remember that bulk inserts and updates are better handled using HQL or JPQL.
  • The CriteriaBuilder, CriteriaQuery, and Root classes are central to the Criteria API, providing a rich set of methods for creating database queries.

For inserts and updates, you should use traditional methods like persist() and merge(), and for bulk updates or deletes, JPQL or HQL is recommended.

Post a Comment

Previous Post Next Post