2.1 表级链接
我们已经看到 Hibernate 如何在辅助表中存储集合。现在让我们弄清楚如何组织存储真实实体类的完整表之间的关系。
Hibernate中实体类之间的关系有四种:
- 一对一_ _
- 一对多_ _
- 多对一_ _
- 多对多_ _
我们将从最简单的选项开始分析——多对一。
您已经遇到过 SQL 中表之间的这种关系。它通常是这样的:
ID | 姓名 | 职业 | 薪水 | 年龄 | 加入日期 |
---|---|---|---|---|---|
1个 | 伊万诺夫伊万 | 程序员 | 100000 | 25 | 2012-06-30 |
2个 | 彼得罗夫彼得 | 程序员 | 80000 | 23 | 2013-08-12 |
3个 | 伊万诺夫谢尔盖 | 测试员 | 40000 | 三十 | 2014-01-01 |
4个 | 拉比诺维奇·莫伊沙 | 导演 | 200000 | 35 | 2015-05-12 |
5个 | 基连科阿纳斯塔西娅 | 办公室主管 | 40000 | 25 | 2015-10-10 |
6个 | 瓦斯卡 | 猫 | 1000 | 3个 | 2018-11-11 |
员工表:
该表包含以下列:
- 标识符整数
- 名称VARCHAR
- 职业VARCHAR
- 薪水整数
- 年龄整数
- join_date日期
这就是包含员工任务的任务表的样子:
ID | 员工ID | 姓名 | 最后期限 |
---|---|---|---|
1个 | 1个 | 修复一个前端bug | 2022-06-01 |
2个 | 2个 | 修复后端的一个bug | 2022-06-15 |
3个 | 5个 | 买咖啡 | 2022-07-01 |
4个 | 5个 | 买咖啡 | 2022-08-01 |
5个 | 5个 | 买咖啡 | 2022-09-01 |
6个 | (无效的) | 打扫办公室 | (无效的) |
7 | 4个 | 享受生活 | (无效的) |
8个 | 6个 | 享受生活 | (无效的) |
该表只有 4 列:
- id – 唯一的任务编号(和表中的行);
- employee_id – 分配任务的员工表中的员工 ID;
- 名称——任务的名称和描述;
- deadline - 任务必须完成的时间。
我们看到任务表中的许多行可以引用员工表中的单个条目。这种表级关系称为多对一。
2.2 与Java类级别的关系
除了表级别的通信,您还可以在 Hibernate 中的实体类级别组织通信。这是通过注释完成的@ManyToOne
。
但首先,让我们创建两个类:Employee和EmployeeTask:
@Entity @Table(name="employee")
class Employee {
@Column(name="id")
public Integer id;
@Column(name="name")
public String name;
@Column(name="occupation")
public String occupation;
@Column(name="salary")
public Integer salary;
@Column(name="join_date")
public Date join;
}
第二类存储员工工作:
@Entity @Table(name="task")
class EmployeeTask {
@Column(name="id")
public Integer id;
@Column(name="name")
public String description;
@Column(name="employee_id")
public Integer employeeId;
@Column(name="deadline")
public Date deadline;
}
这些类都很好,但是它们之间没有关系可以反映 EmployeeTask 类的 employeeId 字段引用 Employee 类的 id 字段这一事实。是时候修复它了
2.3 @ManyToOne注解。
首先,在 Java 中我们习惯于操作对象(和对象引用)而不是它们的 id。所以首先,让我们指向一个 Employee 类型的对象,而不是 EmployeeTask 类中的 employeeId 字段。这是我们的新课程的样子:
@Entity @Table(name="task")
class EmployeeTask {
@Column(name="id")
public Integer id;
@Column(name="name")
public String description;
@ManyToOne @JoinColumn(name = "employee_id")
public Employee employee;
@Column(name="deadline")
public Date deadline;
}
在注释 的帮助下@ManyToOne
,我们已经指出许多 EmployeeTask 对象可以引用一个 Employee 类型的对象。此外,使用注释 @JoinColumn
,我们指出了 Employee 对象的 ID 存储在表的哪一列中。
2.4 请求示例
现在让我们展示一些 Hibernate 如何与这些相关类一起工作的例子。
场景一
让我们编写一个查询来找出已分配给特定用户的所有任务。下面是这个查询在 HQL 中的样子:
from EmployeeTask where employee.name = "Ivan Ivanovich"
您可以简单地通过一个点来引用依赖类的字段。很舒服。但是让我们仍然以 Java 代码的形式编写这个查询:
String hql = "from EmployeeTask where employee.name = :username";
Query<EmployeeTask> query = session.createQuery( hql, EmployeeTask.class);
query.setParameter("username", "Ivan Ivanovich");
List<EmployeeTask> resultLIst = query.list();
情景二
让我们编写一个查询,返回一个有逾期任务的员工列表。如果截止日期已过,则任务已过期。下面是该查询在 SQL 中的样子:
SELECT DISTINCT employee.*
FROM task JOIN employee ON task.employee_id = employee.id
WHERE task.deadline < CURDATE();
DISTINCT
之所以使用,是因为可以将许多任务分配给一个用户。
现在让我们用 HQL 编写相同的查询:
select distinct employee from EmployeeTask where deadline < CURDATE();
此查询中的 Employee 是 EmployeeTask 类的一个字段
情况三
将所有未分配的任务分配给主管。SQL 查询将如下所示:
UPDATE task SET employee_id = 4 WHERE employee_id IS NULL
现在让我们用 HQL 编写相同的查询:
update EmployeeTask set employee = :user where employee is null
最后一个查询是最难的。我们需要传递主管的 ID,但是 EmployeeTask 类不包含可以写入 id 的字段,而是包含一个 Employee 字段,我们需要在其中分配对 Employee 类型对象的引用。
Employee director = session.get(Employee.class, 4);
String hql = "update EmployeeTask set employee = :user where employee is null";
Query<EmployeeTask> query = session.createQuery(hql, EmployeeTask.class);
query.setParameter("user", director);
query.executeUpdate();
GO TO FULL VERSION