• 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;
    
  • 相关阅读:
    树莓派4 (1)一键配置
    Android编码学习之Fragment
    android编码学习
    自动化中app支持schema跳转
    jenkins持续集成
    测试环境运维文章集锦
    HTML5 data-* 自定义属性
    了解一下JavaScript的未来——ECMAScript5
    ECMAScript5的其它新特性
    ECMAScript5 Array新增方法
  • 原文地址:https://www.cnblogs.com/weixia-blog/p/13622524.html
Copyright © 2020-2023  润新知