1. Overview
Hibernate is a powerful ORM framework that allows us to focus less on SQL and more on working with Java objects. The Criteria API provides a programmatic way to build database queries and is particularly useful when queries are dynamic and complex.
In this article, we’ll explore how to use Hibernate’s Criteria API to perform group-by operations.
2. Setting up the Model
Let’s create a basic Product entity with category and price fields. We’ll aim to group products by category and calculate the total price per category:
@Entity
public class Product {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private String category;
private Double price;
// Getters and setters omitted for brevity
}
3. Grouping Products Using Criteria API
The Criteria API provides a programmatic way to perform complex queries, including grouping operations.
Let’s create a method that groups products by category and calculates the total price for each category:
public class ProductService {
private SessionFactory sessionFactory;
public ProductService() {
sessionFactory = new Configuration().configure().buildSessionFactory();
}
public List<Object[]> getTotalPricePerCategory() {
try (Session session = sessionFactory.openSession()) {
CriteriaBuilder criteriaBuilder = session.getCriteriaBuilder();
CriteriaQuery<Object[]> query = criteriaBuilder.createQuery(Object[].class);
Root<Product> root = query.from(Product.class);
query.multiselect(
root.get("category"),
criteriaBuilder.sum(root.get("price"))
).groupBy(root.get("category"));
return session.createQuery(query).getResultList();
}
}
}
Let’s dive into the details of what we’re doing in this example:
- We group products by the category field with the groupBy() method of the CriteriaQuery interface.
- Then, we calculate the total price per category using the criteriaBuilder.sum() method.
- The code returns the results as a list of Object[], where each array contains the category and total price.
Let’s also have a look at the generated SQL:
select
p.category c,
sum(p.price) s
from
product p
group by
c
Note that here, we use try-with-resources so we don’t have to worry about closing the Session manually.
4. Unit Test
Now, let’s add a unit test to verify our grouping query:
@BeforeAll
public void setup() {
productService = new ProductService();
// Insert sample data
try (Session session = productService.getSessionFactory().openSession()) {
session.beginTransaction();
Product product1 = new Product("Product1", "Electronics", 100.0);
Product product2 = new Product("Product2", "Electronics", 150.0);
Product product3 = new Product("Product3", "Furniture", 200.0);
session.persist(product1);
session.persist(product2);
session.persist(product3);
session.getTransaction().commit();
}
}
@Test
public void whenGroupedByCategory_thenReturnTotalPrice() {
List<Object[]> results = productService.getTotalPricePerCategory();
Assertions.assertEquals(2, results.size());
results.forEach(record -> {
String category = (String) record[0];
Double totalPrice = (Double) record[1];
if ("Electronics".equals(category)) {
Assertions.assertEquals(250.0, totalPrice);
} else if ("Furniture".equals(category)) {
Assertions.assertEquals(200.0, totalPrice);
}
});
}
Here’s what we do in this test:
- We use a setup method to insert sample data into the database.
- Then, we call the getTotalPricePerCategory() method and validate the results by checking that the total price is correct for each category.
5. Conclusion
In this article, we’ve seen how to perform a group-by query using the Hibernate Criteria API, which provides a type-safe, programmatic approach to querying.
The example code from this tutorial can be found over on GitHub.