首页 > 代码库 > Hibernate自身一对多和多对多关系映射

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

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

 

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

类图:category

                             技术分享

 

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

 

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

[java] view plain copy
 
 print?
  1. public class Category  
  2.   
  3. {  
  4.   
  5. private Long id;  
  6.   
  7. private String name;  
  8.   
  9. private Category parentCategory;  
  10.   
  11. private Set<Category> childCategories;  
  12.   
  13. public Category(String name, Category parentCategory,  
  14.   
  15. Set<Category> childCategories)  
  16.   
  17. {  
  18.   
  19. this.name = name;  
  20.   
  21. this.parentCategory = parentCategory;  
  22.   
  23. this.childCategories = childCategories;  
  24.   
  25. }  
  26.   
  27. public Category()  
  28.   
  29. {  
  30.   
  31. }  
  32.   
  33. *******set、get方法省略  
  34.   
  35. }  



 

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

 

Category.hbm.xml配置文件

 

[html] view plain copy
 
 print?
  1. <?xml version="1.0"?>  
  2.   
  3. <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"  
  4.   
  5. "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">  
  6.   
  7. <hibernate-mapping>  
  8.   
  9. <class name="com.shengsiyuan.hibernate.Category" table="categories">  
  10.   
  11. <id name="id" column="id" type="long">  
  12.   
  13. <generator class="increment"></generator>  
  14.   
  15. </id>  
  16.   
  17. <property name="name" type="string" >  
  18.   
  19. <column name="name" length="50" ></column>  
  20.   
  21. </property>  
  22.   
  23. <set name="childCategories" cascade="all" inverse="true">  
  24.   
  25. <key column="category_id"></key>  
  26.   
  27. <one-to-many class="com.shengsiyuan.hibernate.Category"/>  
  28.   
  29. </set>  
  30.   
  31. <many-to-one name="parentCategory" column="category_id" class="com.shengsiyuan.hibernate.Category">  
  32.   
  33. </many-to-one>  
  34.   
  35. </class>  
  36.   
  37. </hibernate-mapping>  



 

 

下面我们来看一下在自身一对多的关系下进行增删改查的示例:

 

[java] view plain copy
 
 print?
  1. import java.util.HashSet;  
  2.   
  3. import org.hibernate.Session;  
  4.   
  5. import org.hibernate.SessionFactory;  
  6.   
  7. import org.hibernate.Transaction;  
  8.   
  9. import org.hibernate.cfg.Configuration;  
  10.   
  11. public class HibernateTest2  
  12.   
  13. {  
  14.   
  15. private static SessionFactory sessionFactory;  
  16.   
  17. static  
  18.   
  19. {  
  20.   
  21. try  
  22.   
  23. {  
  24.   
  25. sessionFactory = new Configuration().configure()  
  26.   
  27. .buildSessionFactory();  
  28.   
  29. }  
  30.   
  31. catch (Exception ex)  
  32.   
  33. {  
  34.   
  35. ex.printStackTrace();  
  36.   
  37. }  
  38.   
  39. }  
  40.   
  41. public static void main(String[] args)  
  42.   
  43. {  
  44.   
  45. Session session = sessionFactory.openSession();  
  46.   
  47. Transaction tx = null;  
  48.   
  49. try  
  50.   
  51. {  
  52.   
  53. tx = session.beginTransaction();  
  54.   
  55. Category category1 = new Category("level1", null, new HashSet<Category>());  
  56.   
  57. Category category2 = new Category("level2", null, new HashSet<Category>());  
  58.   
  59. Category category3 = new Category("level2", null, new HashSet<Category>());  
  60.   
  61. Category category4 = new Category("level3", null, new HashSet<Category>());  
  62.   
  63. Category category5 = new Category("level3", null, new HashSet<Category>());  
  64.   
  65. Category category6 = new Category("level3", null, new HashSet<Category>());  
  66.   
  67. Category category7 = new Category("level3", null, new HashSet<Category>());  
  68.   
  69. category2.setParentCategory(category1);  
  70.   
  71. category3.setParentCategory(category1);  
  72.   
  73. category1.getChildCategories().add(category2);  
  74.   
  75. category1.getChildCategories().add(category3);  
  76.   
  77. category4.setParentCategory(category2);  
  78.   
  79. category5.setParentCategory(category2);  
  80.   
  81. category2.getChildCategories().add(category4);  
  82.   
  83. category2.getChildCategories().add(category5);  
  84.   
  85. category6.setParentCategory(category3);  
  86.   
  87. category7.setParentCategory(category3);  
  88.   
  89. category3.getChildCategories().add(category6);  
  90.   
  91. category3.getChildCategories().add(category7);  
  92.   
  93. Category category = (Category)session.get(Category.class, new Long(1));  
  94.   
  95. System.out.println(category.getChildCategories().iterator().next().getName());  
  96.   
  97. session.delete(category);  
  98.   
  99. tx.commit();  
  100.   
  101. }  
  102.   
  103. catch(Exception ex)  
  104.   
  105. {  
  106.   
  107. if(null != tx)  
  108.   
  109. {  
  110.   
  111. tx.rollback();  
  112.   
  113. }  
  114.   
  115. }  
  116.   
  117. finally  
  118.   
  119. {  
  120.   
  121. session.close();  
  122.   
  123. }  
  124.   
  125. }  
  126.   
  127. }  
  128.   
  129.    

   

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

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

先简单看一下实体类:

student.java

[java] view plain copy
 
 print?
  1. /** 学生实体类 */  
  2.   
  3. public class Student {  
  4.   
  5. private Long id;                //对象标识符(OID)  
  6.   
  7. private String name;            //姓名  
  8.   
  9. private String grade;           //所在班级  
  10.   
  11. private Set<Course> courses;    //所有所选课程的集合  
  12.   
  13. public Student(){}              //无参数的构造方法  
  14.   
  15. ******set、get方法省略  
  16.   
  17. }  


 

Course.java

[java] view plain copy
 
 print?
  1. /** 课程实体类 */  
  2.   
  3. public class Course {  
  4.   
  5. private Long id;                //对象标识符(OID)  
  6.   
  7. private String name;            //课程名  
  8.   
  9. private Double creditHours;     //课时数  
  10.   
  11. private Set<Student> students;  //选择了这门课程的学生的集合  
  12.   
  13. public Course(){}             //无参数的构造方法  
  14.   
  15. ******set、get方法省略  
  16.   
  17. }  


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

Student.hbm.xml

[html] view plain copy
 
 print?
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2.   
  3. <!DOCTYPE hibernate-mapping PUBLIC  
  4.   
  5.         "-//Hibernate/Hibernate Mapping DTD 3.0//EN"  
  6.   
  7.      "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">  
  8.   
  9. <hibernate-mapping>  
  10.   
  11.   <!-- 映射持久化类 -->  
  12.   
  13. <class name="com.zxf.domain.Student" table="student">  
  14.   
  15. <!-- 映射对象标识符 -->  
  16.   
  17. <id name="id" column="id" type="long">  
  18.   
  19. <generator class="native" />  
  20.   
  21. </id>  
  22.   
  23. <!-- 映射普通属性 -->  
  24.   
  25. <property name="name" />  
  26.   
  27. <property name="grade" />  
  28.   
  29. <!-- 映射集合属性,指定连接表 -->  
  30.   
  31. <set name="courses" table="student_course">  
  32.   
  33. <!-- 用key元素指定本持久类在连接表中的外键字段名 -->  
  34.   
  35. <key column="student_id" />  
  36.   
  37. <!-- 映射多对多关联类 -->  
  38.   
  39.       <many-to-many column="course_id"   
  40.   
  41.        class="com.zxf.domain.Course" />  
  42.   
  43. </set>  
  44.   
  45. </class>  
  46.   
  47. </hibernate-mapping>  
  48.   
  49. Course.hbm.xml:  
  50.   
  51. <?xml version="1.0" encoding="UTF-8"?>  
  52.   
  53. <!DOCTYPE hibernate-mapping PUBLIC  
  54.   
  55.         "-//Hibernate/Hibernate Mapping DTD 3.0//EN"  
  56.   
  57.         "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">  
  58.   
  59. <hibernate-mapping>  
  60.   
  61. <!-- 映射持久化类 -->  
  62.   
  63. <class name="com.zxf.domain.Course" table="course">  
  64.   
  65. <!-- 映射对象标识符 -->  
  66.   
  67. <id name="id" column="id" type="long">  
  68.   
  69. <generator class="native" />  
  70.   
  71. </id>  
  72.   
  73. <!-- 映射普通属性 -->  
  74.   
  75. <property name="name" />  
  76.   
  77. <property name="creditHours" column="credit_hours" />  
  78.   
  79. <!-- 映射集合属性,指定连接表 -->  
  80.   
  81. <set name="students" table="student_course" inverse="true">  
  82.   
  83. <!-- 用key元素指定本持久类在连接表中的外键字段名 -->  
  84.   
  85. <key column="course_id" />  
  86.   
  87. <!-- 映射多对多关联类 -->  
  88.   
  89. <many-to-many column="student_id" class="com.zxf.domain.Student" />  
  90.   
  91. </set>  
  92.   
  93. </class>  
  94.   
  95. </hibernate-mapping>  


下面具体看一下增删改查的具体测试的关键代码:

增加数据测试:

           

[java] view plain copy
 
 print?
  1. <span xmlns="http://www.w3.org/1999/xhtml" style=""><span xmlns="http://www.w3.org/1999/xhtml" style="">tran = session.beginTransaction();  
  2.   
  3. Student stu1 = new Student("xiaoli", "two");  
  4.   
  5. Student stu2 = new Student("xiaoming", "two");  
  6.   
  7. Student stu3 = new Student("xiaoqiang", "two");  
  8.   
  9. Course course1 = new Course("java", 3.0);  
  10.   
  11. Course course2 = new Course("c#", 5.0);  
  12.   
  13. //stuset.add(stu1);  
  14.   
  15. //stuset.add(stu2);  
  16.   
  17. //course1.setStudents(stuset);  
  18.   
  19. //session.save(course1);  
  20.   
  21. couset.add(course1);  
  22.   
  23. couset.add(course2);  
  24.   
  25. stu1.setCourses(couset);  
  26.   
  27. session.save(stu1);  
  28.   
  29. tran.commit();</span></span>  


 

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

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