学生、课程、分数关系的设计与实现 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.

 

posted on 2018-08-14 14:03  wait_for_you  阅读(487)  评论(0编辑  收藏  举报

导航