7、JPA对象关系-双向多对一(mappedBy比较少用)

双向多对一(很少用)

  1. 双向多对一就是 通过A对象可以找到B对象,同理通过B对象可以找到A对象,他们之间互相依赖。
  2. 既然他们互相依赖,在JSON序列化或ToString时就会报出栈内存溢出,并且业务上也很少这样用,基本都是通过主表-找到子表即可,不会通过子表再去查主表。JSON序列化异常,可以通过@JsonBackReference注解解决。
  3. 双向多对一和双向一对多其实是一样的,这里只用双向多对一说明使用方式。
  4. 我们知道单向多对一会在多方添加一列,单向一对多会生成1个中间关系表,那么JPA对双向多对一是如何维护的?
  5. @JoinColumn 手动维护关系,告诉JPA不需要创建关系。

废话不多数,看下面代码

1、实体类定义

@Data
@Entity
public class Employee {
    @Id
    @GeneratedValue
    private long id;
    private String name;

    @ManyToOne
    private Department department;
}

@Data
@Entity
public class Department {
    @Id
    @GeneratedValue
    private long id;
    private String name;

    @OneToMany
    private List<Employee> employees;
}

2、persistence.xml 配置

 <class>com.hongying.entity.many2many.Department</class>
        <class>com.hongying.entity.many2many.Employee</class>

        <exclude-unlisted-classes>true</exclude-unlisted-classes>

3、单元测试类

@Test
    public void save(){
        Department d1=new Department();
        d1.setName("人事部");

        Employee gg=new Employee();
        gg.setName("gg");
        Employee jl=new Employee();
        jl.setName("jl");

        //设置关系
        List<Employee> employees=new ArrayList<>();
        employees.add(gg);
        employees.add(jl);
        d1.setEmployees(employees);

        gg.setDepartment(d1);
        jl.setDepartment(d1);

        //保存
        EntityManager entityManager = JpaUtil.getEntityManager();
        entityManager.getTransaction().begin();

        entityManager.persist(d1);
        entityManager.persist(gg);
        entityManager.persist(jl);

        entityManager.getTransaction().commit();
        entityManager.close();

    }

4、控制台输出

分析:先保存部门,部门ID就有了,发现在保存员工时,department_id插入到员工表了;员工保存后,提交事务时,会发现员工ID有了,部门中员工属性发生变化,从而会中间表插入2条关系;结果就是下面了
从这些SQL语句可知,JPA在@ManyToOne关系维护了1列,在@OneToMany关系又维护了个中间表;

Hibernate: insert into Department (name) values (?)
Hibernate: insert into Employee (department_id, name) values (?, ?)
Hibernate: insert into Employee (department_id, name) values (?, ?)
Hibernate: insert into Department_Employee (Department_id, employees_id) values (?, ?)
Hibernate: insert into Department_Employee (Department_id, employees_id) values (?, ?)

5、JPA维护了2个关系

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

现在对于双向多对一,JPA维护了2个关系,但是我们业务上只需要1个关系就可以了,多出来1个关系也没有意义,并且一旦2个关系不一致了,还不知道应该以哪一方为准。此时如何解决

6、用mappedBy解决双向多对一出现2个关系问题

解决方法很简单,就是让1方放弃关系的维护,通常我们都是让N方放弃关系的维护,这样不用生成一个中间表了。在`@OneToMany 上添加mappedBy属性

@Data
@Entity
public class Department {
    @Id
    @GeneratedValue
    private long id;
    private String name;

    //mappedBy 作用:
    //1、然N方,放弃关系的维护,不创建中间关系表
    //2、N方查找关系时,只需要在Employee的department属性上
    @OneToMany(mappedBy = "department")
    private List<Employee> employees;
}

在这里插入图片描述

JPA 双向时,也不会级联保存

JPA双向多对一,只是查询时,如果使用到依赖数据时,会自动懒加载加载。但是我们只保存部门或员工时,JPA不会依赖把另一方自动保存,必须调用2方的persist方法,都持久化。
如下,当只保存员工时,部门信息不会自动保存,部门ID是NULL

@Test
    public void save(){
        Department d1=new Department();
        d1.setName("人事部");

        Employee gg=new Employee();
        gg.setName("gg");
        Employee jl=new Employee();
        jl.setName("jl");

        //设置关系
        List<Employee> employees=new ArrayList<>();
        employees.add(gg);
        employees.add(jl);
        d1.setEmployees(employees);

        gg.setDepartment(d1);
        jl.setDepartment(d1);

        //保存
        EntityManager entityManager = JpaUtil.getEntityManager();
        entityManager.getTransaction().begin();

//        entityManager.persist(d1);
        entityManager.persist(gg);
        entityManager.persist(jl);

        entityManager.getTransaction().commit();
        entityManager.close();

    }

双向多对一,如何手动维护关系?@JoinColumn

上面关系维护都是由JPA自动在多方添加1列(员工表自动添加部门ID),但是现在员工表和部门表已经自己创建好了,不需要JPA维护关系,如何告诉JPA使用哪个列作为关系键?

@Data
@Entity
public class Employee {
    @Id
    @GeneratedValue
    private long id;
    private String name;

    @ManyToOne
    //name指定的外键列名称。referencedColumnName 外键表的主键名称,默认是主键名称可以不写
    @JoinColumn(name = "department_id",referencedColumnName = "id")
    private Department department;
}

@Data
@Entity
public class Department {
    @Id
    @GeneratedValue
    private long id;
    private String name;

    //mappedBy 作用:
    //1、然N方,放弃关系的维护,不创建中间关系表
    //2、N方查找关系时,只需要在Employee的department属性上
    @OneToMany(mappedBy = "department")
    private List<Employee> employees;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值