Hibernate 查询映射到自定义类
1. 概述
当我们使用 Hibernate 从数据库中检索数据时,默认情况下,它使用检索到的数据为请求的对象构建整个对象图。但有时我们可能只想检索部分数据,最好是扁平结构。
在这个快速教程中,我们将看到如何在 Hibernate 中使用自定义类来实现这一点。
2. 实体
首先,让我们看看我们将用于检索数据的实体:
@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
}
在这里,我们有两个实体—— DeptEmployee和Department。为简单起见,我们假设一个DeptEmployee只能属于一个Department。
但是,一个Department可以有多个DeptEmployees。
3. 自定义查询结果类
假设我们要打印所有员工的列表,其中包含他们的姓名和部门名称。
通常,我们会使用这样的查询来检索这些数据:
Query<DeptEmployee> query = session.createQuery("from com.blogdemo.hibernate.entities.DeptEmployee");
List<DeptEmployee> deptEmployees = query.list();
这将检索所有员工、他们的所有属性、关联的部门及其所有属性。
但是,在这种特殊情况下,这可能有点贵,因为我们只需要员工姓名和部门名称。
仅检索我们需要的信息的一种方法是在 select 子句中指定属性。
但是,当我们这样做时,Hibernate 返回一个数组列表而不是对象列表:
Query query = session.createQuery("select m.name, m.department.name from com.blogdemo.hibernate.entities.DeptEmployee m");
List managers = query.list();
Object[] manager = (Object[]) managers.get(0);
assertEquals("John Smith", manager[0]);
assertEquals("Sales", manager[1]);
我们可以看到,返回的数据处理起来有点麻烦。但是,幸运的是,我们可以让 Hibernate 将这些数据填充到一个类中。
让我们看一下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
}
请注意,该类不是实体,而只是 POJO。但是,我们也可以使用实体,只要它有一个构造函数,该构造函数将我们想要填充的所有属性作为参数。
我们将在下一节中了解为什么构造函数很重要。
4. 在 HQL 中使用构造函数
现在,让我们看看使用这个类的 HQL:
Query<Result> query = session.createQuery("select new com.blogdemo.hibernate.pojo.Result(m.name, m.department.name)"
+ " from com.blogdemo.hibernate.entities.DeptEmployee m");
List<Result> results = query.list();
Result result = results.get(0);
assertEquals("John Smith", result.getEmployeeName());
assertEquals("Sales", result.getDepartmentName());
在这里,我们使用我们在Result类中定义的构造函数以及我们想要检索的属性。这将返回一个Result对象列表,其中包含从列中填充的数据。
正如我们所见,返回的列表比使用对象数组列表更容易处理。
需要注意的是,我们必须在查询中使用类的完全限定名。
5. 使用 ResultTransformer
在 HQL 查询中使用构造函数的另一种方法是使用ResultTransformer:
Query query = session.createQuery("select m.name as employeeName, m.department.name as departmentName"
+ " from com.blogdemo.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());
我们使用 *Transformers.aliasToBean()*方法使用检索到的数据来填充 Result对象。
因此,我们必须确保 select 语句中的列名或其别名与 Result类的属性相匹配。
注意Query.setResultTransformer(ResultTransformer) 自 Hibernate 5.2 以来已被弃用。