8、Spring Data JPA 之 表与表关系建立(一对多)
一对多
Employee 和 Department 两个实体类,部门与员工存在一对多的关系
部门表
@Entity
@Table(name = "t_department")
public class Department {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "department_id")
private Integer departmentId;
@Column(name = "address")
private String address;
@Column(name = "phone_number")
private String phoneNumber;
/**
* 使用注解的形式配置多表之间的关系(一对多关系)
* 1声明关系
* @OneToMany
* targetEntity = Employee.class 对方对象的字节码对象
* mappedBy: 对方配置关系的属性名称
* cascade: 配置级联
* 2配置外键
* @JoinColumn
* name 外键字段名称
* referencedColumnName 参照的主表的主键字段名称
* 在一的一方添加了外键配置,对于一的一方也具备了维护外键的作用
*/
// @OneToMany(targetEntity = Employee.class)
// @JoinColumn(name = "fk_department_employee", referencedColumnName = "department_id")
@OneToMany(mappedBy = "department", cascade = CascadeType.ALL)
private Set<Employee> employees = new HashSet<>();
public Set<Employee> getEmployees() {
return employees;
}
public void setEmployees(Set<Employee> employees) {
this.employees = employees;
}
public Integer getDepartmentId() {
return departmentId;
}
public void setDepartmentId(Integer departmentId) {
this.departmentId = departmentId;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public String getPhoneNumber() {
return phoneNumber;
}
public void setPhoneNumber(String phoneNumber) {
this.phoneNumber = phoneNumber;
}
@Override
public String toString() {
return "Department{" +
"departmentId=" + departmentId +
", address='" + address + '\'' +
", phoneNumber='" + phoneNumber + '\'' +
'}';
}
}
员工表
/**
* 1.实体类和表的映射关系
* @Entity
* @Table
* 2.类中属性和表中字段的映射关系
* @Id
* @GeneratedValue
* @Column
*/
@Entity
@Table(name = "t_employee")
public class Employee{
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "emp_id")
private Integer empId;
@Column(name = "user_name")
private String userName;
@Column(name = "gender")
private String gender;
/**
* 配置多对一的关系
* 配置表关系
* 配置外键(中间表)
*/
@ManyToOne(targetEntity = Department.class)
@JoinColumn(name = "fk_department_employee", referencedColumnName = "department_id")
private Department department;
public Department getDepartment() {
return department;
}
public void setDepartment(Department department) {
this.department = department;
}
public Integer getEmpId() {
return empId;
}
public void setEmpId(Integer empId) {
this.empId = empId;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
@Override
public String toString() {
return "Employee{" +
"empId=" + empId +
", userName='" + userName + '\'' +
", gender='" + gender + '\'' +
'}';
}
}
接口
import java.util.List;
/**
* 符合Spring Data Jpa 的 dao层接口规范
* JpaRepository<操作的实体类类型,实体类中主键属性的类型>
* #封装了基本CRUD操作
* JpaSpecificationExecutor <操作的实体类类型>
* #封装了复杂查询(分页)
*/
public interface DepartmentDao extends JpaRepository<Department, Integer>,JpaSpecificationExecutor<Department>{
}
/**
* 符合Spring Data Jpa 的 dao层接口规范
* JpaRepository<操作的实体类类型,实体类中主键属性的类型>
* #封装了基本CRUD操作
* JpaSpecificationExecutor <操作的实体类类型>
* #封装了复杂查询(分页)
*/
public interface EmployeeDao extends JpaRepository<Employee, Integer>,JpaSpecificationExecutor<Employee>{
}
测试
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:applicationContext.xml")//指定spring容器的配置信息
public class OneToManyTest {
@Autowired
private DepartmentDao departmentDao;
@Autowired
private EmployeeDao employeeDao;
/**
* 保存员工与部门
*/
@Test
@Transactional
@Rollback(false)
public void testAdd(){
Department department = new Department();
department.setAddress("南海省");
department.setPhoneNumber("8888-8888");
Employee employee = new Employee();
employee.setGender("男");
employee.setUserName("小黑");
/**
* 配置了部门 → 员工 的关系(一对多的关系)
* 从员工的角度上,发送两条insert语句,发送一条更新语句更新数据库(更新外键)
* 由于我们配置了员工 → 部门 的关系,员工可以对外键进行维护
*/
department.getEmployees().add(employee);
departmentDao.save(department);
employeeDao.save(employee);
}
@Test
@Transactional
@Rollback(false)
public void testAdd1(){
Department department = new Department();
department.setAddress("南海省");
department.setPhoneNumber("8888-8888");
Employee employee = new Employee();
employee.setGender("男");
employee.setUserName("小黑");
/**
* 配置了员工→部门的关系(多对一的关系)
* 只发送了两条insert语句
* 由于配置了员工 → 部门的映射关系(多对一)
*/
employee.setDepartment(department);
departmentDao.save(department);
employeeDao.save(employee);
}
@Test
@Transactional
@Rollback(false)
public void testAdd2(){
Department department = new Department();
department.setAddress("南海省");
department.setPhoneNumber("8888-8888");
Employee employee = new Employee();
employee.setGender("男");
employee.setUserName("小黑");
/**
* 会有一条多余的语句update
* 由于一的一方可以委会外键,会发送update语句
* 解决此问题,只需要在一的一方放弃维护权即可
* 放弃外键维护权
* mappedBy 对方配置关系的属性名称
*/
department.getEmployees().add(employee);//由于配置了多的一方 → 一的一方的关联关系(当保存的时候,就已经对外键赋值)
employee.setDepartment(department); //由于配置了 一的一方→ 多的一方的关联关系(发送了一条update语句)
departmentDao.save(department);
employeeDao.save(employee);
}
/**
* 级联添加,保存一个部门的同时,保存部门的所有员工
* 需要在操作主体的实体类上,配置casacde属性
*/
@Test
@Transactional
@Rollback(false)
public void testCaseCascadeAdd(){
Department department = new Department();
department.setAddress("南海省");
Employee employee = new Employee();
employee.setUserName("小黑");
employee.setDepartment(department);
department.getEmployees().add(employee);
departmentDao.save(department);
}
/**
* 级联删除
* 删除部门的同时,删除部门下的所有员工
*/
@Test
@Transactional
@Rollback(false)
public void testCascadeRemove(){
//查询部门
Department department = departmentDao.findOne(1);
//删除部门
departmentDao.delete(department);
}
}