zoukankan      html  css  js  c++  java
  • 一口一口吃掉Hibernate(五)——一对多单向关联映射

          在上一篇博客《一口一口吃掉Hibernate(四)——多对一单向关联映射》中,介绍了多对一的关联映射,今天就反过来说一下一对多的单向关联映射。

          可能有人会对这2篇博客的题目有点混淆不清,跟日常说的关系有点不同。我们日常说的比如父子关系,夫妻关系都是说的双向关系,而现在讨论的则是单向关系,所以也就有了多对一和一对多的说法。

          二者的关系其实很简单,只是角度不同而已。比如说学生和班级的关系。如果从学生角度来看,是多对一的关系。而从班级角度来看,则是一对多的关系。说法很简单,但是在对象和关系的建立却是不一样的。

          先看一下一对多的类图(貌似好多人的聚合关系都画错了):

         hibernate对于一对多的关系的处理,是通过操作Class端,间接操作或者自动操作Student端。比如添加,我直接添加Class端的数据,多个Student就会被添加自动添加进去。也可以通过这个Class获取到所有对应的学生信息。跟着我来配置一下吧:

          首先定义实体类【Class】【Student】

    1. package com.bjpowernode.hibernate;  
    2.   
    3. import java.util.Set;  
    4.   
    5. /** 
    6.  * 班级类 
    7.  * @author Longxuan 
    8.  * 
    9.  */  
    10. public class Class {  
    11.   
    12.     private int id;  
    13.       
    14.     private String name;  
    15.       
    16.     private Set<Student> students;  
    17.   
    18.     public Set<Student> getStudents() {  
    19.         return students;  
    20.     }  
    21.   
    22.     public void setStudents(Set<Student> students) {  
    23.         this.students = students;  
    24.     }  
    25.   
    26.     public int getId() {  
    27.         return id;  
    28.     }  
    29.   
    30.     public void setId(int id) {  
    31.         this.id = id;  
    32.     }  
    33.   
    34.     public String getName() {  
    35.         return name;  
    36.     }  
    37.   
    38.     public void setName(String name) {  
    39.         this.name = name;  
    40.     }  
    41. }  
    42.   
    43.   
    44. package com.bjpowernode.hibernate;  
    45.   
    46. /** 
    47.  * 学生类 
    48.  * @author Longxuan 
    49.  * 
    50.  */  
    51. public class Student {  
    52.   
    53.     private int id;  
    54.       
    55.     private String name;  
    56.       
    57.     public int getId() {  
    58.         return id;  
    59.     }  
    60.   
    61.     public void setId(int id) {  
    62.         this.id = id;  
    63.     }  
    64.   
    65.     public String getName() {  
    66.         return name;  
    67.     }  
    68.   
    69.     public void setName(String name) {  
    70.         this.name = name;  
    71.     }  
    72.   
    73.       
    74. }  

          hibernate.cfg.xml配置文件和hibernate.properties配置文件跟上篇博文中的一致,只是数据库名不同而已。自行修改或者不修改都可。

          Hibernate提供了one-to-many来简化一对多的映射关系。不用我们自己再去实现,只需要在映射文件中进行配置即可:

    1. <?xml version="1.0"?>  
    2. <!DOCTYPE hibernate-mapping PUBLIC   
    3.     "-//Hibernate/Hibernate Mapping DTD 3.0//EN"  
    4.     "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">  
    5. <hibernate-mapping package="com.bjpowernode.hibernate">  
    6.     <class name="Student" table="t_student">  
    7.         <id name="id">  
    8.             <generator class="native"/>  
    9.         </id>  
    10.         <property name="name"/>  
    11.     </class>  
    12.       
    13.     <class name="Class" table="t_class">  
    14.         <id name="id">  
    15.             <generator class="native"/>  
    16.         </id>  
    17.         <property name="name"/>  
    18.         <!-- 设置Set,用于关联多个学生 -->  
    19.         <set name="students">  
    20.             <!-- 在t_student表中创建外键classid,与本表的id对应 -->  
    21.             <key column="classid"></key>  
    22.             <one-to-many class="Student"></one-to-many>  
    23.         </set>  
    24.     </class>    
    25.       
    26. </hibernate-mapping>  
          配置了one-to-many会自动在t_student表中创建外键classid,与t_class的id映射。

          测试类【One2ManyTest】:

    1. package com.bjpowernode.hibernate;  
    2.   
    3. import java.util.HashSet;  
    4. import java.util.Iterator;  
    5. import java.util.Set;  
    6. import junit.framework.TestCase;  
    7. import org.hibernate.Session;  
    8. import org.hibernate.Transaction;  
    9.   
    10. public class One2ManyTest extends TestCase {  
    11.           
    12.     public void testSave2() {  
    13.         Session session = null;  
    14.         try {  
    15.             session = HibernateUtils.getSession();  
    16.             session.beginTransaction();  
    17.               
    18.             Student student1 = new Student();  
    19.             student1.setName("张三");  
    20.             //必须先将student1转化为Persistent状态,否则会抛TransientObjectException  
    21.             session.save(student1);  
    22.               
    23.             Student student2 = new Student();  
    24.             student2.setName("李四");  
    25.             //必须先将student1转化为Persistent状态,否则会抛TransientObjectException  
    26.             session.save(student2);  
    27.               
    28.             Class classes = new Class();  
    29.             classes.setName("提高班");  
    30.               
    31.             Set<Student> students = new HashSet<Student> ();  
    32.             students.add(student1);  
    33.             students.add(student2);  
    34.             classes.setStudents(students);  
    35.               
    36.             //可以成功保存数据。  
    37.             //先添加数据,将关系字段设置为null,再用update语句来更新关系字段  
    38.             //但是会发出多余的update语句来维持关系。  
    39.             session.save(classes);  
    40.             session.getTransaction().commit();  
    41.            
    42.         }catch(Exception e) {  
    43.             e.printStackTrace();  
    44.             session.getTransaction().rollback();  
    45.         }finally {  
    46.             HibernateUtils.closeSession(session);  
    47.         }  
    48.     }     

          结果图:

          执行测试前: ,执行测试后:

          虽然最后的结果跟多对一一样,但是根据sql语句,就可以看出,一对多是先添加student,classid为null,等添加了class以后,再执行update语句,把classid更新上去。这样同时可能会暴露一个问题:如果student的classid设置了not-null="true",则会抛PropertyValueException异常。所以不太推荐使用一对多。

          通过上面的例子,我们可以看出,其实一对多关联映射和多对一关联映射映射原理是一致的,都是在多的一端加入一个外键,指向一的一端。


          它们的区别在于维护的关系不同:

    • 多对一维护的关系是:多指向一的关系,有了此关系,在加载多的时候可以将一加载上来
    • 一对多维护的关系是:一指向多的关系,有了此关系,在加载一的时候可以将多加载上来

          在一的一端维护关系存在缺陷:

    • 因为多的一端Student不知道Class的存在(也就是Student没有维护与Class的关系)所以在保存Student的时候关系字段classid是为null的,如果将该关系字段设置为非空,则将无法保存数据
    • 另外因为Student不维护关系,而Class维护关系,Class就会发出多余的update语句,保证Class和Student有关系,这样加载Class的时候才可以把该Class对应的学生加载上来
  • 相关阅读:
    Gridview利用DataFormatString属性设置数据格式
    Sqlserver 字符串操作
    解决“网络不存在或尚未启动”
    ASP.NET中Url重写后,打不开真正的Html页面
    jquery 清空表单
    Sqlserver2005远程访问
    FCKeditor 在Ie中弹出“未知工具栏项目”的暂时解决方法
    表单成功提交了,点后退显示网页过期
    找不到方法:“Void System.Web.UI.HtmlControls.HtmlForm.set_Action(System.String)”。
    LINQ 标准的查询操作符 设置操作符号 两个结果集的 并、交、差、唯一
  • 原文地址:https://www.cnblogs.com/KingIceMou/p/7100982.html
Copyright © 2011-2022 走看看