• JPA中@OneToOne、@OneToMany、@ManyToMany的映射关系


    @OneToOne

    单向关系

    假设学生和学生卡是一对一关系,那么:

    学生类:

    import lombok.Data;
    
    import javax.persistence.*;
    import java.io.Serializable;
    
    @Entity
    @Data
    @Table(name = "student")
    public class Student implements Serializable {
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        private Long id;
    
        @Column(nullable = false)
        private String name;
    
        @OneToOne(cascade = CascadeType.ALL)
        @JoinColumn(name = "card_id")
        private Card card;
    }
    

    学生卡类:

    import lombok.Data;
    
    import javax.persistence.*;
    import java.io.Serializable;
    
    @Entity
    @Table(name = "card")
    @Data
    public class Card implements Serializable {
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        private Long id;
    
        @Column(nullable = false)
        private Integer number;
    }
    

    生成的数据库表如下:

    • @OneToOne和@JoinColumn定义了关系维护端
    • 关系维护端(Student)生成的数据库表包含外键,关系被维护端(Card)生成的数据库表不包含外键
    • 当保存关系维护端(Student)前,会先保存关系被维护端(Card),同时更新外键值;
    • 如果设置了级联删除,当删除关系维护端(Student)时,关系被维护端(Card)将一块被删除;否则只删除关系维护端(Student)自己
    • 单向关系只保证关系维护端(Student)的每个实例有且只有一个Card实例,但无法保证一个关系被维护端(Card)的实例只被一个关系维护端(Student)的实例引用即一张学生卡可能对应多个人
    • 当删除关系被维护端(Card)时,程序报错Cannot delete or update a parent row: a foreign key constraint fails,是由于被维护端的数据被通过外键引用无法删除

    双向

    如果更改为双向关系,只需改动关系被维护端:

    import lombok.Data;
    
    import javax.persistence.*;
    import java.io.Serializable;
    
    @Entity
    @Table(name = "card")
    @Data
    public class Card implements Serializable {
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        private Long id;
    
        @Column(nullable = false)
        private Integer number;
        
        @OneToOne(mappedBy = "card")
        private Student student;
    }
    
    • @OneToOne的mappedBy属性定义了关系被维护端,表示主动让出放弃维护权,由当前被标注字段所属类型(Student类)的类属性名(card属性名)负责维护关系,类属性名是当前类的实例或实例集合
    • 关系维护端(Student)生成的数据库表包含外键,关系被维护端(Card)生成的数据库表不包含外键
    • 当保存关系维护端(Student)前,会先保存关系被维护端(Card),同时更新外键值;如果通过关系被维护端来保存关系维护端实例,关系维护端实例会保存,但外键值为空或不更新
    • 双向关系保证关系维护端(Student)的每个实例有且只有一个Card实例,同时保证关系被维护端(Card)的实例只被一个关系维护端(Student)的实例引用

    @OneToMany

    单向

    假设一个学校有多个教师,那么:

    学校类:

    import lombok.Data;
    
    import javax.persistence.*;
    import java.io.Serializable;
    import java.util.List;
    
    @Entity
    @Table(name = "school")
    @Data
    public class School implements Serializable {
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        private Long id;
    
        @Column(nullable = false)
        private String name;
    
        @OneToMany(cascade = CascadeType.ALL)
        @JoinColumn(name = "schoolIDid")
        private List<Teacher> teacherList;
    }
    

    教师类:

    import lombok.Data;
    
    import javax.persistence.*;
    import java.io.Serializable;
    import java.util.List;
    
    @Entity
    @Table(name = "teacher")
    @Data
    public class Teacher implements Serializable{
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        private Long id;
    
        @Column(nullable = false)
        private String name;
    
        @ManyToOne
        @JoinColumn(name = "schoolIDid")
        private School school;
    }
    

    生成的数据库表如下:

    在一对多关系中,多的一方是关系维护端即@ManyToOne定义关系维护端,@OneToMany定义关系被维护端

    关系维护端生成的数据库表包含外键,关系被维护端生成的数据表不包含外键。

    关系维护端负责外键记录的更新,关系被维护端没有权利更新外键字段

    @JoinColumn作用:

    • 阻止生成中间表。如果想阻止生成中间表,关系被维护端(一的一方)必须标注@JoinColumn
    • 指定外键名。默认外键名为关系被维护端的表名加下划线加id,如果指定外键名则关系维护端和关系被维护端都必须标注@JoinColumn

    如果关系被维护端没有使用@JoinColumn,那么数据库会生成中间表:

    不同于一对一关系,关系维护端保存前必须先维护关系被维护端,否则报错

    双向

    只须在关系被维护端的@OneToMany注解中添加mappedBy属性

    @MonyToMony

    单向

    一对多和一对一关系,可以用外键实现;多对多关系只能通过中间表进行映射。

    假设一个学生有多个老师,一个老师有多个学生,那么:

    关系维护端注解如下:

    @ManyToMany (cascade = CascadeType.REFRESH)
     
    @JoinTable (//关联表
     
    name = "student_teacher" , //关联表名
     
    inverseJoinColumns = @JoinColumn (name = "teacher_id" ),//被维护端外键
     
    joinColumns = @JoinColumn (name = "student_id" )       //维护端外键
    )
    private Set<Teacher> teachers;
    

    关系被维护端注解如下:

    @ManyToMany (fetch = FetchType.LAZY)
     
    @JoinTable (//关联表
     
    name = "student_teacher" , //关联表名
     
    inverseJoinColumns = @JoinColumn (name = "student_id" ),//被维护端外键
     
    joinColumns = @JoinColumn (name = "teacher_id" )       //维护端外键
    )
    private Set<Student> students;
    
    • 关系维护端删除时,如果中间表存在些纪录的关联信息,则会删除该关联信息
    • 关系被维护端删除时,如果中间表存在些纪录的关联信息,则会删除失败

    关联表名 = 主表表名+_下划线+从表表名

    joinColumns属性=当前实体类数据库表名+_下划线+id

    双向

    关系维护端注解不变,关系被维护端注解更改为:

    @ManyToMany (fetch = FetchType.LAZY, 
                 mappedBy = "teachers",         //通过维护端的属性关联
                 cascade = CascadeType.REFRESH
    )
    private Set<Student> students;
    
  • 相关阅读:
    Windows server 2016 解决“无法完成域加入,原因是试图加入的域的SID与本计算机的SID相同。”
    Windows Server 2016 辅助域控制器搭建
    Windows Server 2016 主域控制器搭建
    Net Framework 4.7.2 覆盖 Net Framework 4.5 解决办法
    SQL SERVER 2012更改默认的端口号为1772
    Windows下彻底卸载删除SQL Serever2012
    在Windows Server2016中安装SQL Server2016
    SQL Server 创建索引
    C#控制台或应用程序中两个多个Main()方法的设置
    Icon cache rebuilding with Delphi(Delphi 清除Windows 图标缓存源代码)
  • 原文地址:https://www.cnblogs.com/weixia-blog/p/13622524.html
Copyright © 2020-2023  润新知