JPA关系映射
四种映射关系
在关系数据库中, 有表与表存在下面几种关系
- 多对一关系(Many-to-One)
- 一对一关系(One-to-One)
- 一对多关系(One-to-Many)
- 多对多关系(Many-to-Many)
也对应这JPA中四种映射关系.
单值串联
从一个实体实例关联到另一个实体实例上, 其中目标基数为1, 成为单值关联(single-valued association).
多对一关系和一对一关系都是属于这一类, 因为源实体至多引用了一个目标实体.
多对一关联(ManyToOne)
来看这么一个关系, 员工(employee)和部门(department)之间的关系, 显然一个员工只能属于一个部门, 而一个部门
内当然拥有多个员工, 所以从员工到部门的映射关系是多对一关系.
employee实体类
@Entity
public class Employee {
@Id
private Integer id;
private String name;
private Long salary;
@ManyToOne
private Department department;
public Employee() {
}
public Employee(Integer id) {
this.id = id;
}
}
department实体类
@Data
@Entity
public class Department {
@Id
private Integer id;
private String name;
}
程序运行后, jpa创建表的sql语句如下
+------------+--------------------------------------+
| Table | Create Table |
+------------+--------------------------------------+
| department | CREATE TABLE `department` ( |
| | `id` int(11) NOT NULL, |
| | `name` varchar(255) DEFAULT NULL, |
| | PRIMARY KEY (`id`) |
| | ) ENGINE=InnoDB DEFAULT CHARSET=utf8 |
+------------+--------------------------------------+
+----------+---------------------------------------------------------------------------------------------------------+
| Table | Create Table |
+----------+---------------------------------------------------------------------------------------------------------+
| employee | CREATE TABLE `employee` ( |
| | `id` int(11) NOT NULL, |
| | `name` varchar(255) DEFAULT NULL, |
| | `salary` bigint(20) DEFAULT NULL, |
| | `department_id` int(11) DEFAULT NULL, |
| | PRIMARY KEY (`id`), |
| | KEY `FKbejtwvg9bxus2mffsm3swj3u9` (`department_id`), |
| | CONSTRAINT `FKbejtwvg9bxus2mffsm3swj3u9` FOREIGN KEY (`department_id`) REFERENCES `department` (`id`) |
| | ) ENGINE=InnoDB DEFAULT CHARSET=utf8 |
+----------+---------------------------------------------------------------------------------------------------------+
department_id是jpa创建的外键, 如果想指定外键的名字, 可以通过@JoinColumn来声明外键的名字
一对一映射
对于员工来说, 只有一个停车位(PackingSpace), 所以员工对停车位来说是一对一映射关系
修改EMPLOYEE类
@Data
@Entity
public class Employee {
@Id
private Integer id;
private String name;
private Long salary;
@ManyToOne
@JoinColumn(name = "dept_id")
private Department department;
@OneToOne
@JoinColumn(name = "p_space_id")
private ParkingSpace parkingSpace;
public Employee() {
}
public Employee(Integer id) {
this.id = id;
}
}
创建PackingSpace实体类
@Data
@Entity
public class ParkingSpace {
@Id
private Integer id;
private String location;
}
查看parking_space表和employee表
+---------------+-----------------------------------------+
| Table | Create Table |
+---------------+-----------------------------------------+
| parking_space | CREATE TABLE `parking_space` ( |
| | `id` int(11) NOT NULL, |
| | `location` varchar(255) DEFAULT NULL, |
| | PRIMARY KEY (`id`) |
| | ) ENGINE=InnoDB DEFAULT CHARSET=utf8 |
+---------------+-----------------------------------------+
+----------+---------------------------------------------------------------------------------------------------------+
| Table | Create Table |
+----------+---------------------------------------------------------------------------------------------------------+
| employee | CREATE TABLE `employee` ( |
| | `id` int(11) NOT NULL, |
| | `name` varchar(255) DEFAULT NULL, |
| | `salary` bigint(20) DEFAULT NULL, |
| | `dept_id` int(11) DEFAULT NULL, |
| | `p_space_id` int(11) DEFAULT NULL, |
| | PRIMARY KEY (`id`), |
| | KEY `FKaqchbcb8i6nvtl9g6c72yba0p` (`dept_id`), |
| | KEY `FKd383146ko181lfhm1xuy3arci` (`p_space_id`), |
| | CONSTRAINT `FKaqchbcb8i6nvtl9g6c72yba0p` FOREIGN KEY (`dept_id`) REFERENCES `department` (`id`), |
| | CONSTRAINT `FKd383146ko181lfhm1xuy3arci` FOREIGN KEY (`p_space_id`) REFERENCES `parking_space` (`id`) |
| | ) ENGINE=InnoDB DEFAULT CHARSET=utf8 |
+----------+---------------------------------------------------------------------------------------------------------+
双向一对一映射
对于员工来说, 至多只能拥有一个停车位, 对于停车位来说, 也至多只能属于一个员工, 所以两个方向都是一对一关系, 这被称为双向一对一关系
修改ParkingSpace实体类
@Data
@Entity
public class ParkingSpace {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
private String location;
@OneToOne(mappedBy = "parkingSpace")
@JoinColumn(name = "emp_id")
private Employee employee;
@Override
public String toString() {
return "ParkingSpace{" +
"id=" + id +
", location='" + location + '\'' +
'}';
}
}
在双向一对一关系中, 如果双方都有mapperBy, name这样是不合法, 如果双方都没有mapperBy, 这样是不正确的, 因为如果双方都没有mapperBy,
则当前不是双向一对一关系, 而是两个单向的一对一关系.
集合值关联
当源实体引用一个或者多个目标实体实例时, 将使用一个多值关联(many-valued association). 一对多关联和多对多映射都符合
一对多映射
前面对于员工来说, 对于部门是多对一映射, 多个员工属于一个部门, 相反的, 对于部门来说, 对员工是一对多的映射, 对于一个部门来说, 拥有多个员工,
所以也是双向的关系
修改department实体类
@Data
@Entity
public class Department {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
private String name;
@OneToMany(mappedBy = "department")
private List<Employee> employees;
}
多对多映射
员工与项目的关系也是多对多的关系, 一个员工大概率不会只会做一个项目, 一个项目大概率也不会只交给一个员工做
增加项目实体类
@Data
@Entity
public class Project {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
private String name;
@ManyToMany(mappedBy = "projects")
private List<Employee> employees;
}
在员工实体类中添加如下
@ManyToMany
private List<Project> projects;
查看创建的表
+---------------------+
| Tables_in_db_projpa |
+---------------------+
| department |
| employee |
| employee_projects |
| hibernate_sequence |
| parking_space |
| project |
+---------------------+
可以看到除了创建project表外, 还创建了表employee_projects表, 没有对这个连接表进行配置, 是根据jpa默认规则进行创建的, 创表的sql语句为
+-------------------+-------------------------------------------------------------------------------------------------------+
| Table | Create Table |
+-------------------+-------------------------------------------------------------------------------------------------------+
| employee_projects | CREATE TABLE `employee_projects` ( |
| | `employees_id` int(11) NOT NULL, |
| | `projects_id` int(11) NOT NULL, |
| | KEY `FKg10a7uho2lylw8g080l5j4gyk` (`projects_id`), |
| | KEY `FK88mdj5vmp7md19u4cbq154dk6` (`employees_id`), |
| | CONSTRAINT `FK88mdj5vmp7md19u4cbq154dk6` FOREIGN KEY (`employees_id`) REFERENCES `employee` (`id`), |
| | CONSTRAINT `FKg10a7uho2lylw8g080l5j4gyk` FOREIGN KEY (`projects_id`) REFERENCES `project` (`id`) |
| | ) ENGINE=InnoDB DEFAULT CHARSET=utf8 |
+-------------------+-------------------------------------------------------------------------------------------------------+
使用@JoinTable来配置连接表
修改员工实体类, 添加@JoinTable注解
@ManyToMany
@JoinTable(name = "emp_proj", joinColumns = @JoinColumn(name = "emp_id"), inverseJoinColumns = @JoinColumn(name = "proj_id"))
private List<Project> projects;
可以看到表名和字段名都相应变化了
+----------+-------------------------------------------------------------------------------------------------+
| Table | Create Table |
+----------+-------------------------------------------------------------------------------------------------+
| emp_proj | CREATE TABLE `emp_proj` ( |
| | `emp_id` int(11) NOT NULL, |
| | `proj_id` int(11) NOT NULL, |
| | KEY `FKj350n5wr8yyesit27cw0agpjq` (`proj_id`), |
| | KEY `FK10tf71i5h7os8kdrpm2k97gn2` (`emp_id`), |
| | CONSTRAINT `FK10tf71i5h7os8kdrpm2k97gn2` FOREIGN KEY (`emp_id`) REFERENCES `employee` (`id`), |
| | CONSTRAINT `FKj350n5wr8yyesit27cw0agpjq` FOREIGN KEY (`proj_id`) REFERENCES `project` (`id`) |
| | ) ENGINE=InnoDB DEFAULT CHARSET=utf8 |
+----------+-------------------------------------------------------------------------------------------------+
参考资料
Pro JPA 2: 精通Java持久化API