《Hibernate学习笔记十二》学生、课程、分数关系的设计与实现

《Hibernate学习笔记十二》学生、课程、分数关系的设计与实现

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

先考虑数据库表

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

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

3、分数表

分数表有两种解决方案

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

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

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

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

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

下面开始设计

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

Student类

@Entity
    public class Student {

    private int id;
    private String name;
    /*
     * Student和Course是多对多的关系,
     * 由于我们一般需要通过Student来获取Course,而不需要通过Course来获取Student,
     * 因此我们建立一个单向导向
     * */
    private Set<Course> courses=new HashSet<Course>();
    @ManyToMany(cascade=CascadeType.ALL)
    //设置中间表,中间表必须的名称必须与Score一致
    @JoinTable(name = "score",
            joinColumns = @JoinColumn(name="student_id"),
            inverseJoinColumns = @JoinColumn(name="course_id")
        )
    public Set<Course> getCourses() {
        return courses;
    }
    public void setCourses(Set<Course> courses) {
        this.courses = courses;
    }
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }

}

Course类

@Entity
public class Course {

    private int id;
    private String name;
    private Set<Student> students=new HashSet<Student>();
    @ManyToMany(mappedBy="courses")
    public Set<Student> getStudents() {
        return students;
    }
    public void setStudents(Set<Student> students) {
        this.students = students;
    }
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }

}

Score类

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

@Entity
@Table(name="score")
public class Score {

    private int id;
    /*
     * Score与Student、Course都是多对一的关联关系,
     * 且Student、Course是多对多的关联关系
     * */
    private Student student;
    private Course course;
    private int score;

    @Id
    @GeneratedValue
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    @ManyToOne
    @JoinColumn(name="student_id")
    public Student getStudent() {
        return student;
    }
    public void setStudent(Student student) {
        this.student = student;
    }
    @ManyToOne
    @JoinColumn(name="course_id")
    public Course getCourse() {
        return course;
    }
    public void setCourse(Course course) {
        this.course = course;
    }

    public int getScore() {
        return score;
    }
    public void setScore(int score) {
        this.score = score;
    }

}

这样我们就完成了实体类的设计。

测试

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

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);

    }

建表语句如下:

从建表语句可以看出,生成的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();

    }

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

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

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

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

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

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

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

时间: 2024-10-13 22:52:12

《Hibernate学习笔记十二》学生、课程、分数关系的设计与实现的相关文章

《Hibernate学习笔记十》:多对多关联关系详解

<Hibernate学习笔记十>:多对多关联关系 前面介绍了一对一.多对一和一对多的关联关系在Hibernate应如何实现,这篇博文就来介绍下最后一种关联关系:多对多.多对多关联关系在我们现实生活中的例子实在是太多太多,最典型的就是老师和学生的例子:一个老师可以教多个学生,而一个学生又可以被多个老师来教. 了解一点数据库的我们都知道,在数据库中表示多对多的关联关系,是借助于中间表来解决的. 如下: 还是和以往的思路一样,每一种关联关系都分为单向关联和双向关联,我们每种都会进行介绍,对于单向和双

Swift学习笔记十二:下标脚本(subscript)

下标脚本就是对一个东西通过索引,快速取值的一种语法,例如数组的a[0].这就是一个下标脚本.通过索引0来快速取值.在Swift中,我们可以对类(Class).结构体(structure)和枚举(enumeration)中自己定义下标脚本的语法 一.常规定义 class Student{ var scores:Int[] = Array(count:5,repeatedValue:0) subscript(index:Int) -> Int{ get{ return scores[index];

虚拟机VMWare学习笔记十二 - 将物理机抓取成虚拟机

1. 安装VMware vCenter Converter Standalone Client 运行虚拟机,File -- Virtualize a Physical Machine 这时如果电脑中没有VMware vCenter Converter Standalone Client ,则会进行安装. 安装过程 之后图标会出现在桌面上,双击运行 选择连接到本地服务器,登陆 点击转换计算机 这个,可以将本地计算机抓取成虚拟机,也可以将其他可以访问的计算机(需知道管理员用户名及密码)抓取成虚拟机.

laravel3学习笔记(十二)

原作者博客:ieqi.net ==================================================================================================== 请求反射 HTTP 协议本身是无状态性的,但是在应用中处理各种业务逻辑时我们必须要有状态的把控,这样,折中的办法就是将状态进行标记然后嵌入到 HTTP 协议的请求中,然后应用根据这些标记来进行状态的串联以及处理.所以我们就要对请求进行反射处理以获取请求信息, Lara

hibernate学习笔记之二(初识hibernate)

(hibernate学习笔记系列来自于 "疯狂Java" 视频学习) Hibernate概述 免费开源Java包,可以使程序和数据库的交互变得容易,并更加符合面向对象的设计. 持久化:将数据保存到数据库中 hibernate持久化类步骤 环境搭建 导入jar包,在hibernate包里的\lib\required文件夹里 导入mysql的JDBC驱动 将上述包添加到路径里面 编写持久化类 要求: 在持久化类中一般需要一个id,通常用Integer类型,这样之后操作会使用null,而不是

java jvm学习笔记十二(访问控制器的栈校验机制)

欢迎装载请说明出处:http://blog.csdn.net/yfqnihao 本节源码:http://download.csdn.net/detail/yfqnihao/4863854 这一节,我们会简单的描述一下jvm访问控制器的栈校验机制. 这节课,我们还是以实践为主,什么是栈校验机制,讲一百遍不如你自己实际的代码一下然后验证一下,下面我们下把环境搭起来. 第一步,配置系统环境.(copy吧,少年) path=%JAVA_HOME%/bin JAVA_HOME=C:/Java/jdk1.6

Hibernate学习笔记(十) — HQL查询

一.HQL的一对多查询 班级(1)->(多)学生 /** * 实现Classes与Student的内连接 * * SELECT c.*,s.* * from classes c INNER JOIN student s * where (c.cid=s.cid) */ @Test public void testInnerJoin(){ session = HibernateUtils.openSession(); Query query = session.createQuery("fr

Hibernate学习笔记(二)

一.hibernate配置文件的两个配置项 hbm2ddl.auto:该属性可帮助程序员实现正向工程, 即由 java 代码生成数据库脚本, 进而生成具体的表结构. . 取值 create | update | create-drop | validate create : 会根据 .hbm.xml 文件来生成数据表, 但是每次运行都会删除上一次的表 ,重新生成表, 哪怕二次没有任何改变 create-drop : 会根据 .hbm.xml 文件生成表,但是SessionFactory一关闭,

OC学习笔记十二 多态

一.多态概念 多态的前提,必须存在继承关系,在代码中的表现形式就是父类类型保存子类类型,即父类的指针指向子类对象. 二.多态特性 在OC中,调用方法是,会检测对象的真实类型,称为动态绑定. 父类保存子类指针,在调用方法时,有以下步骤: 1).在编译的时候,会检查 父类指向子类的指针 调用的方法,在父类中是否存在,如果有,编译通过 2).在运行时,会动态检测 初始对象 的真实类型 三.多态用途 提供动态绑定特性,减少不必要的程序冗余.在方法中,把父类当成参数,使该方法具备调用所有子类同样方法的能力