• 学生、课程、分数关系的设计与实现 Hibernate


    转载自  https://blog.csdn.net/u010412719/article/details/51353806 

     

    Hibernate 学生、课程、分数关系的设计与实现

    这个马士兵老师的Hibernate视频学习的一个题目,这里面要用到多对多、多对一的关联关系以及联合主键,因此觉得挺好的,自己写篇博文来记录下。

    先考虑数据库表

    1、学生表:为简单起见,只考虑了学生id和学生姓名,其中id为主键

    2、课程表:为简单起见,只考虑了课程id和课程名称,其中id为主键

    3、分数表

    分数表有两种解决方案

    3.1 第一种为:使用联合主键:student_id 和 course_id

    3.2 第二种:不使用联合主键,而使用id作为主键

    在这里,这篇博文所采取的方法是采用第二种方法:即不使用联合主键,使用id作为主键

    在考虑实体类,以及它们的映射关系

    一个学生可以选择多个课程,一个课程可以被多个学生选择,即学生和课程是一个多对多的关系。而一个学生可以有多个分数,因此,分数与学生是多对一的关系,同理,分数与课程也是多对一的关系。

    下面开始设计

    Student实体与Course类之间时多对多的关系,但是,一般情况下,我们需要通过学生来获取他的全部课程,因此,我们需要这样一个导向,有时,我们也需要通过课程,来提取选择这门课的学生,因此,我们建立双向关联。

    Student类

     1 @Entity
     2     public class Student {
     3 
     4     private int id;
     5     private String name;
     6     /*
     7      * Student和Course是多对多的关系,
     8      * 由于我们一般需要通过Student来获取Course,而不需要通过Course来获取Student,
     9      * 因此我们建立一个单向导向
    10      * */
    11     private Set<Course> courses=new HashSet<Course>();
    12     @ManyToMany(cascade=CascadeType.ALL)
    13     //设置中间表,中间表必须的名称必须与Score一致
    14     @JoinTable(name = "score",
    15             joinColumns = @JoinColumn(name="student_id"),
    16             inverseJoinColumns = @JoinColumn(name="course_id")
    17         )
    18     public Set<Course> getCourses() {
    19         return courses;
    20     }
    21     public void setCourses(Set<Course> courses) {
    22         this.courses = courses;
    23     }
    24     @Id
    25     @GeneratedValue(strategy = GenerationType.AUTO)
    26     public int getId() {
    27         return id;
    28     }
    29     public void setId(int id) {
    30         this.id = id;
    31     }
    32     public String getName() {
    33         return name;
    34     }
    35     public void setName(String name) {
    36         this.name = name;
    37     }
    38 
    39 }

    Course类

     1 @Entity
     2 public class Course {
     3 
     4     private int id;
     5     private String name;
     6     private Set<Student> students=new HashSet<Student>();
     7     @ManyToMany(mappedBy="courses")
     8     public Set<Student> getStudents() {
     9         return students;
    10     }
    11     public void setStudents(Set<Student> students) {
    12         this.students = students;
    13     }
    14     @Id
    15     @GeneratedValue(strategy = GenerationType.AUTO)
    16     public int getId() {
    17         return id;
    18     }
    19     public void setId(int id) {
    20         this.id = id;
    21     }
    22     public String getName() {
    23         return name;
    24     }
    25     public void setName(String name) {
    26         this.name = name;
    27     }
    28 
    29 }
    •  

    Score类

    Score与Student、Course都是多对一的关联关系,因此,我们需要建立ManyToOne的关联关系。

     1 @Entity
     2 @Table(name="score")
     3 public class Score {
     4 
     5     private int id;
     6     /*  一个课程可以有多个成绩(88,98,。。)  一个学生可以有多个分数(数学,物理,。。)
     7      * Score与Student、Course都是多对一的关联关系,
     8      * 且Student、Course是多对多的关联关系 
     9      * */
    10     private Student student;
    11     private Course course;
    12     private int score;
    13 
    14     @Id
    15     @GeneratedValue
    16     public int getId() {
    17         return id;
    18     }
    19     public void setId(int id) {
    20         this.id = id;
    21     }
    22     @ManyToOne
    23     @JoinColumn(name="student_id")
    24     public Student getStudent() {
    25         return student;
    26     }
    27     public void setStudent(Student student) {
    28         this.student = student;
    29     }
    30     @ManyToOne
    31     @JoinColumn(name="course_id")
    32     public Course getCourse() {
    33         return course;
    34     }
    35     public void setCourse(Course course) {
    36         this.course = course;
    37     }
    38 
    39     public int getScore() {
    40         return score;
    41     }
    42     public void setScore(int score) {
    43         this.score = score;
    44     }
    45 
    46 
    47 }

    测试

    通过如下的代码可以观察建表语句。

    public  void testSchema(){
            ServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder().configure().build();
            Metadata metadata = new MetadataSources(serviceRegistry).buildMetadata();
            SchemaExport schemaExport = new SchemaExport();
            schemaExport.create(EnumSet.of(TargetType.DATABASE), metadata);
    
    
        }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    建表语句如下:

    从建表语句可以看出,生成的Score表是采用的是student_id和course_id的联合主键,而在Score实体类中,我们是采用的@Id来修饰的id,Hibernate并没有按照@id来进行生成表,而是根据Student类和Course实体类的中间表score来进行生成的。

    由于生成的表与我们的目的我不符合,因此,我们可以选择手动建表,建表语句如下:

    测试Save方法,即持久化对象

    有一个学生,学了两门课,有两个成绩

    @Test
    public void testSave(){
            /*
             * 有一个学生,学了一门课,有一个成绩
             * */
            Student s1=new Student();
            s1.setName("wu");
    
    
            Course c1=new Course();
            c1.setName("math");
            Course c2=new Course();
            c2.setName("english");
            /*
             * 困惑:加上如下的两条语句将会发出两条insert into score values(null,null);
                 * */
        //      s1.getCourses().add(c1);
        //      s1.getCourses().add(c2);
    
            Score sc1=new Score();
            sc1.setScore(98);
            sc1.setStudent(s1);
            sc1.setCourse(c1);
    
            Score sc2=new Score();
            sc2.setScore(77);
            sc2.setStudent(s1);
            sc2.setCourse(c2);
    
            //开启事务进行持久化操作
            Session s=sessionFactory.getCurrentSession();
            s.beginTransaction();
            s.save(s1);     
            s.save(c1); 
            s.save(c2);     
            s.save(sc1);
            s.save(sc2);    
            s.getTransaction().commit();
    
        }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40

    正确的持久化的结果在数据库中结果如下:

    在测试中,当我们在测试代码中,加上如下的两行代码(这两行代码在上面的代码块中已注释掉了),

    s1.getCourses().add(c1);
    s1.getCourses().add(c2);//这两行代码的意图就是将课程加入到学生中
    • 1
    • 2

    就会得到如下的结果:即为我们自动生成了两行成绩为NULL的行数据。

    遇到的问题:Field ‘id’ doesn’t have a default value

    在完成这个测试的过程中,遇到了如下的问题:

    原因是我们手动建表时,没有为主键id设置auto_increment.

  • 相关阅读:
    JVM如何执行方法调用
    JVM如何实现反射
    JVM是如何处理异常的
    Java类加载
    windows-Kafka安装
    Google Eventbus简单使用
    队列c#版
    python 元类

    Spring Mvc 笔记二之异常和文件上传
  • 原文地址:https://www.cnblogs.com/kwaitfort/p/9474293.html
Copyright © 2020-2023  润新知