表分析

数据库表与表之间的关系

  • 多对多
    • 工程师—项目
    • 老师—学生
  • 一对多
    • 学校—班级
    • 班级—学生
  • 一对一
    • 学生—学生证
    • 公民—身份证

image-20200402202254173

JPA中的一对多

一的一方为主表;多的一方为从表;从表依赖主表存在

  • 首先,确定两张表之间的关系
  • 在数据库中实现两张表的关系外键
  • 在实体类中描述两个实体的关系
  • 配置初实体类和数据库表的关系映射

@OneToMany

JPA中的多对多

@ManyToMany

JPA中的一对一

@OneToOne

问题描述

在利用Spring boot data JPA进行表设计的时候,表对象之间经常存在各种映射关系,如何正确将理解的映射关系转化为代码中的映射关系是关键之处。

解决办法

概念理解

  • 举例:在公司的权限管理中,存在公司表、部门表、员工表。
    1. 公司表和部门表的关系:
      主控方:部门表
      被控方:公司表
    2. 部门表和员工表的关系:
      由于是多对多的关系,不存在谁是主控方或被控方,两者处于平行关系。
  • 一对多或多对一,用外键关联,若未设置级联删除,则删除被控方记录的时候会有外键约束。
  • 多对多,用中间表关联,删除中间表的记录,不会各方的表造成影响。
  • 在该四个注解中,都含有属性可设置,以下举例两个属性。
    1. fetch=FetchType.LAZY为默认的数据延迟加载,fetch=FetchType.EAGER为急加载。
    2. cascade={CascadeType.PERSIST,CascadeType.MERGE,
      CascadeType.REFRESH,CascadeType.REMOVE}.
      其中:
      CascadeType.PERSIST级联新增(又称级联保存);
      CascadeType.MERGE:级联合并(级联更新);
      CascadeType.REMOVE:级联删除;
      CascadeType.REFRESH:级联刷新
      CascadeType.ALL:以上四种都是;
      一般采用CascadeType.MERGE:级联合并(级联更新)即可。默认值是均不进行关联。

@OneToOne

  • 在一对一的关系中,只需在主控方(数据总表)内注明@OneToOne,而被控方(员工表)只是作为外键,不需任何特殊标记。
@Entity
@Table(name = "costume_all_id")
public class AllId extends AbstractEntity {
    private static final long serialVersionUID = 1L;

    @OneToOne(cascade = CascadeType.ALL)
    @JoinColumn(name = "costume_member_fk")
    private Member member;// 用户表外键
}

@OneToMany和@ManyToOne

  • 公司(组织)表相对于部门表是被控方,只需在被控方写mappedBy,其值为主控方中引用的外键对象的名称。
@Entity
@Table(name = "costume_organization")
public class Organization extends AbstractEntity {
    private static final long serialVersionUID = 1L;

    @Column(nullable = false, length = 50)
    private String name; // 组织名称

    @OneToMany(mappedBy = "organization")
    private Set<Department> departmentSet; // 部门集合
}
  • 部门表相对于公司(组织)表是主控方,在主控方只需写@ManyToOne即可,其对象名为被控表中mappedBy中的值。
  • 同时需要注意,如果需要将公司表对象或者部门表对象转为JSON数据的时候,为了防止出现无限循环包含对方,需要在部门表(多的一方)的引用公司表(少的一方)对象的set方法上写上注解@JsonBackReference
@Entity
@Table(name = "costume_department")
public class Department extends AbstractEntity {
    private static final long serialVersionUID = 1L;

    @Column(nullable = false, length = 50)
    private String name; // 部门名称

    @ManyToOne(optional = false)
    private Organization organization; // 组织外键

    @ManyToMany
    private Set<Member> memberSet; // 用户表外键

    public Organization getOrganization() {
        return organization;
    }

    @JsonBackReference
    public void setOrganization(Organization organization) {
        this.organization = organization;
    }
}

@ManyToMany

  • 在多对多的情况下,如部门表和员工表之间的关系(暂不去深究一个员工是否能有多个部门的身份)。
  • 部门表和员工表只需在引用对象集合上注明@ManyToMany即可,其中部门表的写法如上段代码,员工表的写法如下段代码。
  • 在多对多的映射中会生成一张中间表,其表名和字段名均有默认的命名规则,若需指定表名和字段名,只需在两者的一方或双方写上@JoinTable注解即可,详情如下代码段,表名属性name=”table_name”,与joinColumns属性是同级属性,即写在其前即可。
  • 同时需要注意,如果需要将员工表对象或者部门表对象转为JSON数据的时候,为了防止出现无限循环包含对方,需要在一方的引用对方对象的set方法(Set对象的set方法)上写上注解@JsonBackReference
@Entity
@Table(name = "costume_member")
public class Member extends AbstractEntity {
    private static final long serialVersionUID = 1L;

    @Column(nullable = false, length = 20)
    private String name;

    @ManyToMany
    @JoinTable(joinColumns = { @JoinColumn(name = "member_id") }, inverseJoinColumns = {
            @JoinColumn(name = "department_id") }) //被控方表字段名
    private Set<Department> departmentSet; // 部门表外键

    public Set<Department> getDepartmentSet() {
        return departmentSet;
    }

    @JsonBackReference
    public void setDepartmentSet(Set<Department> departmentSet)
    {
        this.departmentSet = departmentSet;
    }
}


JAVA   SpringData JPA      JAVA SpringData JPA

本博客所有文章除特别声明外,均采用 CC BY-SA 3.0协议 。转载请注明出处!