Mastering Hibernate Query Language (HQL)
Hibernate Query Language (HQL) provides an object-oriented approach to database retrieval. While its syntax resembles standard SQL, HQL operates on persistent entities and they attributes rather than database tables and columns. It natively supports object-oriented paradigms like inheritance, polymorphism, and associations.
Core Principles
- Queries follow the
SELECT FROMpattern but target Java class and property names instead of table and column names. - Keywords are case-insensitive, but Java class names, packages, and property names are strictly case-sensitive.
- If multiple registered entities share the same simple class name, fully qualified names (including the package) must be specified to avoid ambiguity.
Basic Entity Retrieval
Configuration cfg = new Configuration().configure();
SessionFactory sf = cfg.buildSessionFactory();
Session sess = sf.openSession();
String hql = "from Customer";
org.hibernate.Query<Customer> q = sess.createQuery(hql, Customer.class);
List<Customer> results = q.list();
for (Customer c : results) {
System.out.println(c.getFullName());
}
sess.close();
Projection and Result Types
1. Scalar Value
Aggregations return a single object. Note that HQL requires count(*) instead of count(1) for row counting.
String hql = "select count(*) from Customer";
org.hibernate.Query q = sess.createQuery(hql);
Number count = (Number) q.uniqueResult();
System.out.println(count.intValue());
2. Object Arrays
Retrieving specific fields yields a list of Object[].
String hql = "select c.fullName, c.years from Customer c";
org.hibernate.Query q = sess.createQuery(hql);
List<Object[]> rows = q.list();
for (Object[] row : rows) {
System.out.println("Name: " + row[0] + ", Age: " + row[1]);
}
3. Maps
Aliasing fields inside new map returns a list of maps.
String hql = "select new map(c.fullName as name, c.years as age) from Customer c";
org.hibernate.Query q = sess.createQuery(hql);
List<Map> maps = q.list();
for (Map m : maps) {
System.out.println("Name: " + m.get("name") + ", Age: " + m.get("age"));
}
4. DTOs / Entities Partial results can be injected directly into a class via a custom constructor.
// Constructor: public Staff(Long id, String name)
String hql = "select new Staff(s.id, s.name) from Staff s";
org.hibernate.Query q = sess.createQuery(hql);
List<Staff> staffList = q.list();
for (Staff s : staffList) {
System.out.println("ID: " + s.getId() + ", Name: " + s.getName());
}
Filtering and Parameter Binding
Named parameters are strongly recommended over positional indices for readability and safety.
String hql = "from Staff s where s.name = :staffName";
org.hibernate.Query q = sess.createQuery(hql);
q.setString("staffName", "JOHN");
List<Staff> staffList = q.list();
for (Staff s : staffList) {
System.out.println(s.getName());
}
Pagination
Hibernate abstracts dialect-specific pagination logic into two simple methods.
String hql = "from Staff";
org.hibernate.Query q = sess.createQuery(hql);
q.setFirstResult(0); // Offset
q.setMaxResults(10); // Limit
List<Staff> page = q.list();
for (Staff s : page) {
System.out.println(s.getName());
}
Object Navigation
Traversing relationships is simplified using property paths, eliminating the need for explicit joins for basic filtering.
String hql = "from Staff s where s.department.id = :deptId";
org.hibernate.Query q = sess.createQuery(hql);
q.setInteger("deptId", 5);
Explicit Joins
HQL supports inner and outer joins. Since relationships are mapped via annotations or XML, the ON clause is implicit.
String hql = "select s.name, d.name from Staff s left join s.department d";
org.hibernate.Query q = sess.createQuery(hql);
Native SQL Fallback
For complex scenarios where HQL falls short, native SQL can be executed directly.
// Returning Object Arrays
String sql = "select name, salary from staff_table where id = :empId";
org.hibernate.SQLQuery sq = sess.createSQLQuery(sql);
sq.setInteger("empId", 100);
List<Object[]> rows = sq.list();
for (Object[] row : rows) {
System.out.println(row[0] + "-" + row[1]);
}
// Returning Mapped Entities
String sqlEntity = "select * from staff_table where id = :empId";
org.hibernate.SQLQuery sqEntity = sess.createSQLQuery(sqlEntity);
sqEntity.setInteger("empId", 100);
sqEntity.addEntity(Staff.class);
List<Staff> staffList = sqEntity.list();
for (Staff s : staffList) {
System.out.println(s.getName() + "-" + s.getSalary());
}