Hibernate自身一对多和多对多关系映射

一对多关系映射大家都明白,关系双方都一个含有对方多个引用,但自身一对多很多同学都不明白什么意思,那么首先我就说明一下什么是自身一对多,其实也很好理解,自身一对多就是自身含有本身的多个引用,例如新闻类别,新闻包含体育新闻和政治新闻,体育新闻内有含有足球新闻和篮球新闻,其实他们都属于新闻,只是名字不同而已,下面我们就以新闻类别为例来具体说明一下:

首先我们来看一下新闻类别的类图:

类图:category

 

从上面的图我们可以看出:每一个新闻类别都有一个父类别和一个孩子类别的set集合,这个父类别和孩子类别里面都是自身的引用,这样就行了自身一对多的对象关系

下面看一下具体的新闻实体类:Category.java

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
public class Category{

  private Long id;

  private String name;

  private Category parentCategory;

  private Set<Category> childCategories;

  public Category(String name, Category parentCategory,

  Set<Category> childCategories){

    this.name = name;

    this.parentCategory = parentCategory;

    this.childCategories = childCategories;

  }

  public Category(){

  }

*******set、get方法省略

}

看完具体的实体类之后我们下面看一下其具体的配置,其实他的配置中没什么特别的地方,仅仅只是他的配置中包含了一对多和多对一的共同标签存在而已:他即含有多的一方的<set>标签。也含有一的一方的<many-to-one>标签:

Category.hbm.xml配置文件

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="com.shengsiyuan.hibernate.Category" table="categories">
  <id name="id" column="id" type="long">
    <generator class="increment"></generator>
  </id>
  <property name="name" type="string" >
    <column name="name" length="50" ></column>
  </property>
  <set name="childCategories" cascade="all" inverse="true">
    <key column="category_id"></key>
    <one-to-many class="com.shengsiyuan.hibernate.Category"/>
  </set>
  <many-to-one name="parentCategory" column="category_id" class="com.shengsiyuan.hibernate.Category">
  </many-to-one>
</class>
</hibernate-mapping>

 

在很多实际开发过程中,多对多的映射关系也是比较常见的,最为明显的例子就是我们常用的学生选课示例,一个学生可以选多门课,一门课也可以由多个学生去选,这样就形成了多对多的映射关系,现在我们就以学生选课的实例来看一看多对多关系映射。由于在多对多映射中,双向多对多用的的比较多,并且单向多对多也比较简单,所以我们就以双向多对多进行讲解

我们先把必要的实体类和实体映射文件写好:

先简单看一下实体类:

student.java

1
2
3
4
5
6
7
8
9
10
package com.hsp.domain;

import java.util.Set;

public class Student {
    private Integer id;
    private String name;
    private Set<StuCourse> stuCourses;
    .....
}

Course.java

1
2
3
4
5
6
7
8
9
10
package com.hsp.domain;

import java.util.Set;

public class Course {
    private Integer id;
    private String name;
    private Set<StuCourse> stuCourses;
    .....
}

StuCourse.java

1
2
3
4
5
6
7
8
9
package com.hsp.domain;

public class StuCourse {
    private Integer id;
    private Student student;
    private Course course;
    private Integer grade;
        ......
}

下一步编写实体映射文件:

Student.hbm.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.hsp.domain">
<class name="Student">
<id name="id" type="java.lang.Integer">
<generator class="sequence">
<param name="sequence">stu_seq</param>
</generator>
</id>
<property name="name" type="java.lang.String">
<column name="name" length="64"/>
</property>
<!-- 这里我们配置了one-to-many 一个学生可以对应多个选课记录 -->
<set name="stuCourses">
<key column="student_id"/>
<one-to-many class="StuCourse"/>
</set>
</class>
</hibernate-mapping>

Course.hbm.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.hsp.domain">
<class name="Course">
<id name="id" type="java.lang.Integer">
<generator class="sequence">
<param name="sequence">course_seq</param>
</generator>
</id>
<property name="name" type="java.lang.String">
<column name="name" length="64"/>
</property>
<!-- 配置one-to-many 表示一门课程可以对应多个选课记录 -->
<set name="stuCourses">
<key column="course_id"/>
<one-to-many class="StuCourse"/>
</set>
</class>
</hibernate-mapping>

StuCourse.hbm.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.hsp.domain">
<class name="StuCourse" >
<id name="id" type="java.lang.Integer">
<generator class="sequence">
<param name="sequence">stucourse_seq</param>
</generator>
</id>
<property name="grade" type="java.lang.Integer">
<column name="grade" length="3"/>
</property>
<many-to-one name="course" column="course_id"/>
<many-to-one name="student" column="student_id"/>
</class>
</hibernate-mapping>

关系图:

many-to-many

下面具体看一下的具体测试的关键代码:

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
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
package com.hsp.view;

import java.util.Date;
import java.util.HashSet;
import java.util.Set;

import org.hibernate.Hibernate;
import org.hibernate.Session;
import org.hibernate.Transaction;

import com.hsp.domain.Course;
import com.hsp.domain.StuCourse;
import com.hsp.domain.Student;
import com.hsp.util.HibernateUtil;

public class TestMain {

    /**
     * @param args
     */

    public static void main(String[] args) {
       
        //添加一组Person/idcard
       
        Session s=null;
        Transaction tx=null;
       
        try {
            //我们使用基础模板来讲解.
            s=HibernateUtil.getCurrentSession();
            tx=s.beginTransaction();
       
            //添加一个学生,一门课程,选课
            Student stu1=new Student();
            stu1.setName("小明");
           
            Course course=new Course();
            course.setName("java");
           
            StuCourse sc=new StuCourse();
           
            sc.setCourse(course);
            sc.setStudent(stu1);
           
            //顺序保存.
            s.save(stu1);
            s.save(course);
            s.save(sc);
           
            tx.commit();
           
        } catch (Exception e) {
            e.printStackTrace();
            if(tx!=null){
                tx.rollback();
            }
        }finally{
           
            if(s!=null && s.isOpen()){
                s.close();
            }
        }
    }
}

 

测试结论:如果想保存数据成功,不管是主控方还是被控方,如果想通过一次保存即可把双方数据保存,需要把实体配置中的cascade属性设置为all或者save-update,由于设置为all包含delete,在删除数据中,删除一条信息会导致相对应表的多条或者全部信息被删掉,所以一般配置save-update。

 

除非注明,Coder文章均为原创,转载请以链接形式标明本文地址

本文地址:http://www.alonemonkey.com/hibernate-many-to-many.html

本文链接:http://www.alonemonkey.com/hibernate-many-to-many.html