zoukankan      html  css  js  c++  java
  • JPA(4)表表关联关系

    在我们做数据库设计的时候,最烦的就是各种表之间的关联关系了,关联关系有:一对多,多对一,一对一,其中还有单向和双向的区别.

      1.双向一对多及多对一映射:既然是双向,那么就是同一类的了:双向一对多关系中,必须存在一个关系维护端,在 JPA 规范中,要求 many 的一方作为关系的维护端(owner side), one 的一方作为被维护端(inverse side)。 可以在 one 方指定 @OneToMany 注释并设置 mappedBy 属性,以指定它是这一关联中的被维护端,many 为维护端。 在 many 方指定 @ManyToOne 注释,并使用 @JoinColumn 指定外键名称,讲的比较难理解,下面是代码:

      

    User.java:  
    @OrderBy("id")//指的是取出数据的时候,按照哪一个字段来进行排列,我们这里是按照user表的id字段排序,默认是ASC,完整用法:@OrderBy(value= "group_name ASC, name DESC")    @OneToMany(targetEntity=Phone.class,mappedBy="user")//mappedBy说的就是上面说的被维护端,多的那一端就是维护端,注意mappedBy="xxx" xxx表示的是在另外一个类中关联这个类的那个属性名,在这个例子中是user(需要注意,这里必须是相同的名称,如果不同的话,是会报错的)
    public Set<Phone> getPhones() { return phones; }
    Phone.java   @JoinColumn(name
    ="user_id")//指定在本实体所映射的那个表中关联的外键 @ManyToOne(targetEntity=User.class)// public User getUser() { return user; }

     顺带讲一下,单向多对一的怎么做,对于上面的代码来说,我们只要将User中将被维护的注解给去掉,当然Set<Phone>也需要去掉。

    下面再讲一下单向一对多:

    JPA单向一对多只需要在多的一端使用如下注解:

    @OneToMany(cascade=CascadeType.ALL,fetch=FetchType.LAZY)//级联保存、更新、删除、刷新;延迟加载36  
    @JoinColumn(name="author_id")//在book表增加一个外键列来实现一对多的单向关联 private Set<Book> books = new HashSet<Book>();

    而在Book.java里头不需要任何有关author的信息。

    但是经过测试发现,在Book表中,author_id需要设置允许为空,因为JPA是先往两张表插入新数据,然后再更新Book表中的author_id字段的。

    所以不可以在数据库中设置该外键为空。

    推荐使用双向关系

    2.双向一对一映射:基于外键的 1-1 关联关系:在双向的一对一关联中,需要在关系被维护端(inverse side)中的 @OneToOne 注释中指定 mappedBy,以指定是这一关联中的被维护端。同时需要在关系维护端(owner side)建立外键列指向关系被维护端的主键列。
      

    User.java:   
    @OneToOne(mappedBy="user")//因为需要指定其中一方为被维护段,我们设置user为被维护段,和双向一对多相同,这个名称必须和FirstLover定义User属性的名称一样 public FirstLover getFirstLover() { return firstLover; } FirstLover.java: //使用OneToOne进行一对一的映射,name表示的是关联关系表的外键,注意的是,这个外键是被维护段的主键,所以是unqie的 @JoinColumn(unique=true,name="user_id") @OneToOne public User getUser() { return user; }

    在关联关系中,延迟加载经常是我们考虑的问题,可以使用在我们的这个例子中,可以使用:

        @JoinColumn(unique=true,name="user_id")
        @OneToOne(fetch=FetchType.LAZY)
        public User getUser() {
            return user;
        }

    但是,有这样的情况:user可以不关联firstLover(因为外键是定义在FirstLover表中的),如果有 FirsetLover 关联就设置为代理对象而延迟加载, 如果不存在关联的 FirsetLover 就设置 null, Hibernate 在不读取 FirsetLover  表的情况是无法判断是否有关联有 FirsetLover , 因此无法判断设置 null 还是代理对象, 而统一设置为代理对象,也无法满足不关联的情况, 所以无法使用延迟加载,只 有显式读取 FirsetLover .

    单向一对一的话只需要在上面增加注解就可以了

        @OneToOne(fetch=FetchType.EAGER)
        protected User updateUser;//这样就是将user的id作为我们现在这个注解了的表的外键了。这样子就单向的关联上了

    最后一种就是多对多的关联关系的情况,在双向多对多关系中,我们必须指定一个关系维护端(owner side),可以通过 @ManyToMany 注释中指定 mappedBy 属性来标识其为关系维护端。为了测试,我定义了两个类:

    Student.java:
    package com.hotusm.commom.entity;
    
    import java.util.HashSet;
    import java.util.Set;
    
    import javax.persistence.Entity;
    import javax.persistence.GeneratedValue;
    import javax.persistence.Id;
    import javax.persistence.JoinColumn;
    import javax.persistence.JoinTable;
    import javax.persistence.ManyToMany;
    
    
    
    @Entity
    public class Student {
        
    
        private Integer id;
        
        private String name;
        private String sex;
        
        private String school;
        private Set<Teacher> teachers=new HashSet<>();
        
        @GeneratedValue
        @Id
        public Integer getId() {
            return id;
        }
        public void setId(Integer id) {
            this.id = id;
        }
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }
        public String getSex() {
            return sex;
        }
        public void setSex(String sex) {
            this.sex = sex;
        }
        public String getSchool() {
            return school;
        }
        public void setSchool(String school) {
            this.school = school;
        }
        
        
        @JoinTable(name="teach_stu",//指定中间表的表名,如果没有指定表名,那么默认的名字是:tab1_tab2
                joinColumns={@JoinColumn(name="teacher_id",//指定本类的主键在中间表的外键的字段名称,
                referencedColumnName="ID")},//指定本类的主键是什么,在这个例子中,teach_stu的teacher的id就是本类的主键值
                inverseJoinColumns={@JoinColumn(name="student_id",//和上面是一样的含义,指明另外一个类主键在中间表的名称
                    referencedColumnName="ID" //指定另外一个类的主键是什么,这里都是ID
                        )}
                )
        @ManyToMany//加上多对多的标示
        public Set<Teacher> getTeachers() {
            return teachers;
        }
        public void setTeachers(Set<Teacher> teachers) {
            this.teachers = teachers;
        }
        @Override
        public String toString() {
            return this.name;
        }
    }
    Teacher:
    package com.hotusm.commom.entity;
    
    import java.util.HashSet;
    import java.util.Set;
    
    import javax.persistence.Column;
    import javax.persistence.Entity;
    import javax.persistence.GeneratedValue;
    import javax.persistence.Id;
    import javax.persistence.ManyToMany;
    
    
    @Entity
    public class Teacher {
        
    
        private Integer id;
        
        private String name;
        
        
        private String subjectName;
        
        private Set<Student> students=new HashSet<>();
        
        @GeneratedValue
        @Id
        public Integer getId() {
            return id;
        }
        
        public void setId(Integer id) {
            this.id = id;
        }
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }
        @Column(name="SUBJECT_NAME")
        public String getSubjectName() {
            return subjectName;
        }
        public void setSubjectName(String subjectName) {
            this.subjectName = subjectName;
        }
        
        @ManyToMany(mappedBy="teachers")//指定维护的一方,注意这里的名称是另外一个类的属性名: private Set<Teacher> teachers=new HashSet<>();
        public Set<Student> getStudents() {
            return students;
        }
        public void setStudents(Set<Student> students) {
            this.students = students;
        }
        @Override
        public String toString() {
            
            return this.name;
        }
    }

     基本上,关联关系也就几种了。

  • 相关阅读:
    Codeforces 120F Spiders
    Codeforces 509C Sums of Digits
    Topcoder SRM 497 DIV2 1000 MakeSquare
    codeforces 22B Bargaining Table
    Codeforces 487B Strip
    Codeforces 132C Logo Turtle
    关闭窗口对话框提示 messagedlg应用和showmodal的使用
    如何让窗口显示在电脑屏幕中间
    delphi项目程序输出编译成应用程序文件
    delphi程序项目创建和保存
  • 原文地址:https://www.cnblogs.com/zr520/p/5013442.html
Copyright © 2011-2022 走看看