5.1 一对一沟通的多种形式
两个 Entity 类之间的关系还有另一个有趣且相当具体的情况 - 一对一关系。
我称这种情况非常具体,因为它更多地是关于 Java 对象而不是数据库。在数据库中,表与表之间的关系只有两种选择:
- 表行包含指向另一个表的 ID 的链接。
- 服务表用于多对多关系。
在实体类的情况下,可能有几个注释描述的选项:
- @嵌入式
- 单边OneToOne
- 双边一对一
- @MapsId
下面我们将考虑其中最受欢迎的。
5.2 嵌入式
顺便说一下,我们已经考虑过最简单的一对一@Embedded
通信选项——这是一个注解。在这种情况下,我们有两个类存储在数据库的同一个表中。
假设我们要将用户的地址存储在UserAddress类中:
@Embeddable
class UserAddress {
@Column(name="user_address_country")
public String country;
@Column(name="user_address_city")
public String city;
@Column(name="user_address_street")
public String street;
@Column(name="user_address_home")
public String home;
}
然后我们只需要在User类中添加一个具有此地址的字段:
@Entity
@Table(name="user")
class User {
@Column(name="id")
public Integer id;
@Embedded
public UserAddress address;
@Column(name="created_date")
public Date createdDate;
}
Hibernate 将完成剩下的工作:数据将存储在一个表中,但是在编写 HQL 查询时,您将需要对类字段进行操作。
HQL查询示例:
select from User where address.city = 'Paris'
5.3 单边OneToOne
想象一下现在的情况:我们有一个源表 employee 和一个引用 employee 的任务。但是我们可以肯定地知道最多可以将一项任务分配给一个用户。那么我们就可以用注解来描述这种情况了@OneToOne
。
例子:
@Entity
@Table(name="task")
class EmployeeTask {
@Column(name="id")
public Integer id;
@Column(name="name")
public String description;
@OneToOne
@JoinColumn(name = "employee_id")
public Employee employee;
@Column(name="deadline")
public Date deadline;
}
Hibernate 将确保不仅一个任务有一个用户,而且一个用户只有一个任务。否则,这种情况实际上与@ManyToOne
.
5.4 双边OneToOne
前面的选项可能有点不方便,因为通常您不仅要将员工分配给任务,还要将任务分配给员工。
为此,您可以将 EmployeeTask 字段添加到 Employee 类并为其提供正确的注释。
@Entity
@Table(name="employee")
class Employee {
@Column(name="id")
public Integer id;
@OneToOne(cascade = CascadeType.ALL, mappedBy="employee")
private EmployeeTask task;
}
重要的!employee 表没有task_id字段,而是使用task表的employee_id字段来建立表与表之间的关系。
在对象之间建立连接看起来像这样:
Employee director = session.find(Employee.class, 4);
EmployeeTask task = session.find(EmployeeTask.class, 101);
task.employee = director;
director.task = task;
session.update(task);
session.flush();
要删除链接,还必须从两个对象中删除链接:
Employee director = session.find(Employee.class, 4);
EmployeeTask task = director.task;
task.employee = null;
session.update(task);
director.task = null;
session.update(director);
session.flush();
GO TO FULL VERSION