Persistence top

I just announced the new Spring Boot 2 material, coming in REST With Spring:

>> CHECK OUT THE COURSE

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.

Note that Query.setResultTransformer(ResultTransformerhas been deprecated since Hibernate 5.2.

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.

Persistence bottom

I just announced the new Spring Boot 2 material, coming in REST With Spring:

>> CHECK OUT THE LESSONS

newest oldest most voted
Notify of
RAHUL GOTI
Guest
RAHUL GOTI

4. Using a Constructor in HQL
Is this working for NativeQuery or just works for createQuery only?

Loredana Crusoveanu
Editor

Hey Rahul,

Using the constructor in this manner works only for HQL as the native query uses the database tables and columns and not the Java objects. However, for createNativeQuery you have the option to specify the second Class parameter if you use the default mapping, or use the SqlResultSetMapping class if you want a custom mapping.

More info here:
https://www.thoughts-on-java.org/result-set-mapping-basics/
https://www.baeldung.com/jpa-sql-resultset-mapping

Database
Guest

Nice Post..!!! This is very important blog , thanks for sharing with us. It is very interesting blog which is helpful for all students as well as employee. Do keep Posting .

Eric Martin
Member
Eric Martin

Glad you found it helpful.
Cheers,
Eric