Mapping A Hibernate Query to a Custom Class – 将Hibernate查询映射到一个自定义类中

最后修改: 2018年 9月 16日

中文/混合/英文(键盘快捷键:t)

1. Overview

1.概述

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.

当我们使用Hibernate从数据库中检索数据时,默认情况下,它使用检索到的数据来构建所请求对象的整个对象图。但有时我们可能只想检索部分数据,最好是扁平结构。

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

在这个快速教程中,我们将看到如何在Hibernate中使用一个自定义类来实现这一目标。

2. The Entities

2.实体

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.

这里,我们有两个实体–DeptEmployeeDepartment。为了简单起见,我们假设一个DeptEmployee只能属于一个Department。部门

But, a Department can have multiple DeptEmployees.

但是,一个Department可以有多个DeptEmployees

3. A Custom Query Result Class

3.一个自定义的查询结果类

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:

但是,当我们这样做时,Hibernate会返回一个数组列表,而不是一个对象列表:

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.

我们可以看到,返回的数据处理起来有点麻烦。但是,幸运的是,我们可以让Hibernate将这些数据填充到一个类中。

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

让我们看一下Result类,我们将用它来填充检索到的数据。

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.

请注意,这个类不是一个实体,而只是一个POJO。然而,我们也可以使用一个实体,只要它有一个构造函数,将我们想要填充的所有属性作为参数。

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

我们将在下一节看到为什么构造函数很重要。

4. Using a Constructor in HQL

4.在HQL中使用构造函数

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

现在,让我们看一下使用这个类的HQL。

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.

在这里,我们使用我们在Result类中定义的构造函数,以及我们想要检索的属性。这将返回一个Result对象的列表,其中有从列中填充的数据。

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

5.使用ResultTransformer

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

在HQL查询中使用构造函数的一个替代方法是使用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.

我们使用Transformers.aliasToBean()方法来使用检索的数据来填充Result对象。

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

因此,我们必须确保选择语句中的列名或其别名与Result 类的属性相匹配。

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

请注意,Query.setResultTransformer(ResultTransformer)已经从Hibernate 5.2开始被废弃。

6. Conclusion

6.结论

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.

伴随着这篇文章的源代码可以在GitHub上找到