Mapping A Hibernate Query to a Custom Class

1. Overview

When we use Hibernate to retrieve data from the database, by default, it
uses the retrieved data to construct the whole object graph for the
object requested. But sometimes we might want to retrieve only part of
the data, preferably in a flat structure.

In this quick tutorial, we’ll see how we can achieve this in Hibernate
using a custom class.

2. The Entities

First, let’s look at entities we’ll be using to the retrieve the data:

@Entity
public class DeptEmployee {

    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE)
    private long id;

    private String employeeNumber;

    private String designation;

    private String name;

    @ManyToOne
    private Department department;

    // constructor, getters and setters
}

@Entity
public class Department {

    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE)
    private long id;

    private String name;

    @OneToMany(mappedBy="department")
    private List<DeptEmployee> employees;

    public Department(String name) {
        this.name = name;
    }

    // getters and setters 
}

Here, we have two entities – DeptEmployee and Department. For
simplicity, let’s assume that a DeptEmployee can belong to only one
Department.

But, a Department can have multiple DeptEmployees.

3. A Custom Query Result Class

Let’s say we want to print a list of all employees with just their name
and the name of their department.

Typically, we would retrieve this data with a query like this:

Query<DeptEmployee> query = session.createQuery("from com.baeldung.hibernate.entities.DeptEmployee");
List<DeptEmployee> deptEmployees = query.list();

This will retrieve all employees, all their properties, the associated
department, and all its properties.

But, in this particular case, this might be a bit expensive as we only
need the name of the employee and the name of the department.

One way to only retrieve the information we need is by specifying the
properties in the select clause.

But, when we do this, Hibernate returns a list of arrays instead of a
list of Objects:

Query query = session.createQuery("select m.name, m.department.name from com.baeldung.hibernate.entities.DeptEmployee m");
List managers = query.list();
Object[] manager = (Object[]) managers.get(0);
assertEquals("John Smith", manager[0]);
assertEquals("Sales", manager[1]);

As we can see, the returned data is a bit cumbersome to process. But,
fortunately, we can get Hibernate to populate this data into a class.

Let’s look at the Result class that we’ll use to populate the
retrieved data into:

public class Result {
    private String employeeName;

    private String departmentName;

    public Result(String employeeName, String departmentName) {
        this.employeeName = employeeName;
        this.departmentName = departmentName;
    }

    public Result() {
    }

    // getters and setters
}

Note that the class is not an entity but just a POJO. However, we can
also use an entity as long as it has a constructor that takes all
attributes that we want to populate as parameters.

We’ll see why the constructor is important in the next section.

4. Using a Constructor in HQL

Now, let’s look at the HQL that uses this class:

Query<Result> query = session.createQuery("select new com.baeldung.hibernate.pojo.Result(m.name, m.department.name)"
  + " from com.baeldung.hibernate.entities.DeptEmployee m");
List<Result> results = query.list();
Result result = results.get(0);
assertEquals("John Smith", result.getEmployeeName());
assertEquals("Sales", result.getDepartmentName());

Here, we use the constructor we defined in the Result class along
with the properties we want to retrieve. This will return a list of
Result objects with the data populated from the columns.

As we can see, the returned list is easier to process than using a list
of object arrays.

It’s important to note that we have to use the fully qualified name of
the class in the query.

5. Using a ResultTransformer

An alternative to using a constructor in the HQL query is to use a
ResultTransformer:

Query query = session.createQuery("select m.name as employeeName, m.department.name as departmentName"
  + " from com.baeldung.hibernate.entities.DeptEmployee m");
query.setResultTransformer(Transformers.aliasToBean(Result.class));
List<Result> results = query.list();
Result result = results.get(0);
assertEquals("John Smith", result.getEmployeeName());
assertEquals("Sales", result.getDepartmentName());

We use the Transformers.aliasToBean() method to use the retrieved
data to populate the Result objects.

Consequently, we have to make sure the column names or their aliases in
the select statement match the properties of the Result class.

6. Conclusion

In this article, we saw how a custom class can be used to retrieve data
in a form that is easy to read.

The source code that accompanies this article is
available over
on GitHub
.

Leave a Reply

Your email address will not be published.