首页 > 代码库 > hibernate之关于关联映射的综合应用

hibernate之关于关联映射的综合应用



【hibernate】之关于关联映射的综合应用


1、关联映射如何处理业务逻辑

2、如何指定中间表

3、如何进行级联操作

4、如何解决Hibenrate建表过程中主键错乱问题

现在有三张表

Student(学生表),Course(课程表),Score(学生,课程,分数,表)

那么我们分析业务逻辑可知,学生和课程是多对多的关系,学生和分数表是一对多的关系,课程和分数也是一对多的关系

直接看Annotations配置,在这里我所有的配置都是双向关联,这样在分数,课程,学生,之中,可以任意找到彼此!


@Entity
@Table(name="c_course")
public class Course {
    private Integer id;
    private String coursename;
    private Set<Student> students=new HashSet<Student>();
    private Set<Score> scores=new HashSet<Score>();
     
    @OneToMany(mappedBy="course")//必须指定关系由多的一方维护
    public Set<Score> getScores() {
        return scores;
    }
    public void setScores(Set<Score> scores) {
        this.scores = scores;
    }
    @ManyToMany//指定中间表是s_score
    @JoinTable(name="s_score",joinColumns={@JoinColumn(name="course_id")},
            inverseJoinColumns={@JoinColumn(name="student_id")})
    public Set<Student> getStudents() {
        return students;
    }
    public void setStudents(Set<Student> students) {
        this.students = students;
    }
    @Id
    @GeneratedValue
    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    @Column(name="c_coursename")
    public String getCoursename() {
        return coursename;
    }
    public void setCoursename(String coursename) {
        this.coursename = coursename;
    }
}
(课程表Course)

@Entity
@Table(name="t_student")
public class Student {
    private Integer id;
    private String name;
    private Set<Course> courses=new HashSet<Course>();
    private Set<Score> scores=new HashSet<Score>();
     
    @OneToMany(mappedBy="student")
    public Set<Score> getScores() {
        return scores;
    }
    public void setScores(Set<Score> scores) {
        this.scores = scores;
    }
    @ManyToMany
    @JoinTable(name="s_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
    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    @Column(name="s_name")
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
     
}
(Student学生表)

@Entity
@Table(name="s_score")
public class Score {
    private Integer id;
    private String score;
    private Student student;
    private Course course;
     
    @ManyToOne(cascade={CascadeType.ALL})//配置级联操作
    @JoinColumn(name="student_id")
    public Student getStudent() {
        return student;
    }
    public void setStudent(Student student) {
        this.student = student;
    }
    @ManyToOne(cascade={CascadeType.ALL})
    @JoinColumn(name="course_id")
    public Course getCourse() {
        return course;
    }
    public void setCourse(Course course) {
        this.course = course;
    }
    @Id
    @GeneratedValue
    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    @Column(name="s_score")
    public String getScore() {
        return score;
    }
    public void setScore(String score) {
        this.score = score;
    }
     
}
(分数表,也是中间关联表,Score)

那么问题来了,采用Hibernate自动建表,我们看一下建表语句

12:11:08,169 DEBUG SchemaExport:415 - 
    create table c_course (
        id integer not null auto_increment,
        c_coursename varchar(255),
        primary key (id)
    )
12:11:08,333 DEBUG SchemaExport:415 - 
    create table s_score (
        id integer not null,
        s_score varchar(255),
        course_id integer,
        student_id integer not null auto_increment,
        primary key (student_id, course_id)
    )
12:11:08,455 DEBUG SchemaExport:415 - 
    create table t_student (
        id integer not null auto_increment,
        s_name varchar(255),
        primary key (id)
    )

我们发现在建表是Hibernate默认将student_id和course_id联合作为主键使用,且student_id还是自增

这样显然是不对的,在这里我也实在想不到,好的办法,智能采用一个笨的办法,手动改回来!

大家最好是采用工具操作,因为,你直接create的话,student_id和course_id关联不上student,course的主键ID


ok,到这里,我们的建表基本完成,下面JunitTest

    @Test
    public void add(){
        try {
            Configuration cfg=new Configuration();
            cfg.configure();
            SessionFactory  sessionFactory=cfg.buildSessionFactory();
            Session session=sessionFactory.openSession();
            session.beginTransaction();
            Student student1=new Student();
            student1.setName("张三1");
//          Student student2=new Student();
//          student2.setName("李四");
            Course c1=new Course();
            c1.setCoursename("数学1");
            Course c2=new Course();
            c2.setCoursename("语文1");
//          session.save(student1);
//          session.save(c1);
//          session.save(student2);
//          session.save(c2);
            Score score=new Score();
            score.setScore("901");
            score.setCourse(c1);
            score.setStudent(student1);
            //张三数学90分
            session.save(score);
            Score score2=new Score();
            score2.setCourse(c2);
            score2.setScore("100");
            score2.setStudent(student1);
            session.save(score2);
            session.getTransaction().commit();
            session.close();
            sessionFactory.close();
        } catch (HibernateException e) {
            e.printStackTrace();
        }
    }

ok,大家可以看出,为什么我们最后只需要保存score就行呢?没有session.save()student和course,为什么也能直接保存数据库中?这就是
cascade={CascadeType.ALL}

级联操作,当然我这里配置的是ALL,其实还有4个参数,大家可以自己慢慢研究!

以上添加成功,那么我们直接load试一下;

public void findTest(){
        Configuration cfg=new Configuration();
        cfg.configure();
        SessionFactory  sessionFactory=cfg.buildSessionFactory();
        Session s=sessionFactory.openSession();
        s.beginTransaction();
        Student student=(Student)s.load(Student.class, 2);
        System.out.println("学生姓名"+student.getName());
        for(Course course:student.getCourses()){
            System.out.print("--------"+"课程名称"+course.getCoursename());
            for(Score score:course.getScores()){
                System.out.println("--------"+"课程分数"+score.getScore());
            }
        }
        s.getTransaction().commit();
        s.close();
        sessionFactory.close();
    }

也没问题

update呢?

public void    update(){
        Configuration cfg=new Configuration();
        cfg.configure();
        SessionFactory  sessionFactory=cfg.buildSessionFactory();
        Session s=sessionFactory.openSession();
        s.beginTransaction();
        Student student=(Student)s.load(Student.class,1);
        //我们现在把查询出来语文成绩改为0分
        for(Course course:student.getCourses()){
            System.out.println(course.getCoursename());
            if("语文".equals(course.getCoursename())){
                for(Score score:course.getScores()){
                    if(score.getStudent().getId().equals(student.getId())){
                        score.setScore("0");
                        s.update(score);
                    }
                }
            }
        } 
        s.getTransaction().commit();
        s.close();
        sessionFactory.close();
    }

删除?

@Test
    public void deleteObj(){
        Configuration cfg=new Configuration();
        cfg.configure();
        SessionFactory  sessionFactory=cfg.buildSessionFactory();
        Session s=sessionFactory.openSession();
        s.beginTransaction();
        Student student=(Student)s.load(Student.class,3);
        s.delete(student);
        s.getTransaction().commit();
        s.close();
        sessionFactory.close();
         
    }


ok,到这里基本上,完成Hibernate关联映射的基本操作!


注意,多对多删除的时候,我们一般删除的是中间表数据?但是往往由于外键关联的关系,Hibernate会删除另一张表中的数据来解除关联关系,这就不对了!后续再探讨!








删除?


hibernate之关于关联映射的综合应用