有几种方法可以通过使用@OneToOne注释来映射JPA和Hibernate中的一对一关系,包括
-
带@JoinColumn的外键单向和双向映射
-
共享主键单向和双向映射,带@MapsId和@PrimaryKeyJoinColumn
本指南将向您展示如何进行映射以及每种方法的优缺点
考虑一个人和身份证之间的关系。一个人只有一张身份证,一张身份证只属于一个人
具有@JoinColumn和@OneToOne的外键双向映射
@OneToOne将放置在关系的两个实体上,则 mapBy 属性值指向关系所有者,该所有者在基础表中具有外键列
@Entity
public class Person {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private String name;
@OneToOne(cascade = CascadeType.ALL, optional = false)
@JoinColumn(name = "id_card_id")
private IDCard idCard;
...
}
@Entity
public class IDCard {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
@Column(unique = true, nullable = false)
private String code = UUID.randomUUID().toString();
@OneToOne(mappedBy = "idCard")
private Person person;
...
}
@JoinColumn指定外键列。它具有关联字段名称及其主键列名称的下划线字符串连接的默认名称
需要@OneToOne上的mappedBy
属性才能指定双向映射。如果mappedBy
不存在,JPA 和休眠将创建一个指向关系所有者的冗余外键列
mysql> describe idcard;
+-----------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-----------+--------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| code | varchar(255) | NO | UNI | NULL | |
| person_id | int(11) | NO | UNI | NULL | |
+-----------+--------------+------+-----+---------+----------------+
优点和缺点
-
外键映射比共享主键映射更原生且易于理解
-
父实体可以快速访问 CRUD 操作并将其级联到子关联
动手教程
具有@JoinColumn和@OneToOne的外键单向映射
@OneToOne将仅放置在一对一关系的 1 个实体上。我们不需要指定mappedBy 属性
@Entity
public class Person {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private String name;
@OneToOne(cascade = CascadeType.ALL, optional = false)
@JoinColumn(name = "id_card_id")
private IDCard idCard;
...
}
@Entity
public class IDCard {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
@Column(unique = true, nullable = false)
private String code = UUID.randomUUID().toString();
...
}
@JoinColumn指定外键列。它具有关联字段名称及其主键列名称的下划线字符串连接的默认名称
优点和缺点
-
外键映射比共享主键映射更原生且易于理解
-
外键单向映射比双向映射更不详细
具有@MapsId和@OneToOne的共享主键双向映射
关系的两个实体将使用相同的主键。在子实体中,共享主键也是外键
@Entity
public class Person {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
@OneToOne(cascade = CascadeType.ALL, mappedBy = "person")
private IDCard idCard;
...
}
@Entity
public class IDCard implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
@OneToOne(cascade = CascadeType.ALL, optional = false)
@JoinColumn(name = "person_id")
@MapsId
private Person person;
...
}
@OneToOne两个实体上都有标记。在子实体上,@MapsId标记在与 @OneToOne
@JoinColumn指定外键列。它具有关联字段名称及其主键列名称的下划线字符串连接的默认名称
优点和缺点
-
父实体可以快速访问 CRUD 操作并将其级联到子关联
-
外键映射将比共享主键映射更原生且易于理解
动手教程
具有@PrimaryKeyJoinColumn和@OneToOne的共享主键单向映射
关系的两个实体将使用相同的主键。在子实体中,共享主键也是外键
@Getter @Setter
@Entity
public class Person {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private String name;
...
}
@Entity
public class IDCard {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int personId;
@OneToOne(cascade = CascadeType.ALL, optional = false)
@PrimaryKeyJoinColumn(name = "person_id", referencedColumnName = "id")
private Person person;
@Column(unique = true, nullable = false)
private String code = UUID.randomUUID().toString();
...
}
@OneToOne仅在子实体上与@PrimaryKeyJoinColumn一起标记
优点和缺点
- 父实体无法访问或级联到子关联的 CRUD 操作
动手教程
在本文中,我们快速浏览了在JPA和Hibernate中映射一对一关系的各种方法,以及有关其优缺点的说明