一对多关联映射(双向)

       一对多双向,从实体类上讲究是在“多”的一端持有“一”的实例,并在配置文件中用<many-to-one>标签将其配置上。这里有一点要特别注意,当两边都能够维护关系的时候,推荐让“多”的一端来做,做法上就是在“一”一端映射文件的<set>标签中设置属性inverse="true"。另外,<key>中为“多”一端表设置的外键要和<many-to-one>中设置的外键要一样。
1.实体模型:
 
2.关系模型:
 
3.实体类:
  Student.java
public class Student {
   private Integer id;
   private String name;
   private Classes classes;
   //一系列的 setter.getter方法
  @Override
   public String toString() {
     return "name of student: " + name;
  }
}
   Classes.java
public class Classes {
   private Integer id;
   private String name;
   private Set<Student> students;
   //一系列的setter.getter方法
  @Override
   public String toString() {
     return "name of class: " + name;
  }
}
 
4.映射文件:
   Student.hbm.xml
   < class name ="com.sxt.hibernate.one2many.entity.Student" table ="sxt_hibernate_student" >
     < id name ="id" length ="4" >
       < generator class ="native" > </ generator >
     </ id >
     < property name ="name" length ="10" > </ property >
    <!-- 此处column指定的外键要和对方key中指定的外键一致 -->
     < many-to-one name ="classes" column ="class_id" cascade ="save-update" > </ many-to-one >
   </ class >
    Classes.hbm.xml
   < class name ="com.sxt.hibernate.one2many.entity.Classes" table ="sxt_hibernate_class" >
     < id name ="id" length ="4" >
       < generator class ="native" > </ generator >
     </ id >
     < property name ="name" length ="10" > </ property >
    <!-- 配置集合属性 -->
    <!-- inverse="true"含义,把关联关系交由对方一端维护,而在操作本方数据时不再维护关系.    -->
     < set name ="students" cascade ="save-update" inverse ="true" >
      <!-- key的含义,指在另一端增加的外键指向本主键.
        如果设置上属性not-null="true",表示该外键非空,则在由"一"的一端维护关系时,
        可能导致插入数据异常PropertyValueException.
        
-->
       < key column ="class_id" > </ key >
      <!-- one-to-many含义,指出set集合中的元素类型,以供加载时使用    -->
       < one-to-many class ="com.sxt.hibernate.one2many.entity.Student" />
     </ set >
   </ class >
 
5.hibernate配置文件:
   参见上一篇。
 
6.测试方法:
   public static void main(String[] args) {
    Session session = HibernateUtils.getSession();
    Transaction t = session.beginTransaction();
     try {
       /**
        * 测试插入数据
        */

/*      Classes classes = new Classes();//情况1:从"多"的一端保存(这完全就是个多对一的情况)
      classes.setName("不一班");
        
      Student student1 = new Student();
      student1.setName("志朋");
      student1.setClasses(classes);
      //存储成功.sql语句如下:
      //Hibernate: insert into sxt_hibernate_class (name, id) values (?, ?)
      //Hibernate: insert into sxt_hibernate_student (name, class_id, id) values (?, ?, ?)
      //Hibernate: insert into sxt_hibernate_student (name, class_id, id) values (?, ?, ?)
      //为了不至于出现TransientObjectException,应先保存classes对象或者在<many-to-one>中
         //加上cascade="save-update,all"
      session.save(student1);

      Student student2 = new Student();
      student2.setName("有朋");
      student2.setClasses(classes);
      //由于此时classes已经是持久化对象了,所以此处不会再存储一遍classes了
      session.save(student2);
*/

/*      Student student1=new Student();//情况2:从"一"的一端保存
      student1.setName("志鹏");
        
      Student student2=new Student();
      student2.setName("有朋");
        
      Set<Student> students=new HashSet<Student>();
      students.add(student1);
      students.add(student2);
        
      Classes classes=new Classes();
      classes.setName("不一班");
      classes.setStudents(students);
      //也能正确保存.sql语句如下:
      //如果<set>标签中没有inverse="true":(情况2.1)
      //Hibernate: insert into sxt_hibernate_class (name, id) values (?, ?)
      //Hibernate: insert into sxt_hibernate_student (name, class_id, id) values (?, ?, ?)
      //Hibernate: insert into sxt_hibernate_student (name, class_id, id) values (?, ?, ?)
      //Hibernate: update sxt_hibernate_student set class_id=? where id=?
      //Hibernate: update sxt_hibernate_student set class_id=? where id=?
      //存储过程是这样的:存classes时,由于有cascade="save-update",它会先触发存储student,
      //由于默认inverse=false,student不负责维护关系,所以此时它的class_id为空;然后回来存储classes,而此时
      //classes不得不来维护关系(发出update语句修改student的外键).
        
      //如果<set>标签中有inverse="true":(情况2.2)
      //Hibernate: insert into sxt_hibernate_class (name, id) values (?, ?)
      //Hibernate: insert into sxt_hibernate_student (name, class_id, id) values (?, ?, ?)
      //Hibernate: insert into sxt_hibernate_student (name, class_id, id) values (?, ?, ?)
      //但是插入的student记录class_id字段为空,因为"一"一端不再负责维护关系了.
      //存储过程是这样的:存classes时,由于有cascade="save-update",它会先触发存储student;    
      // 而在存储student时,虽然inverse="true"指明了由它来维护关联关系,所以他要先存主表class,
      // 再回来存副表student,但是student发现它的classes为null,就把class_id字段设为了空.
        
        
      session.save(classes);
*/
        
/*      Classes classes=new Classes();//情况3
      classes.setName("不一班");
        
      Student student1=new Student();
      student1.setName("志鹏");
      student1.setClasses(classes);
        
      Student student2=new Student();
      student2.setName("有朋");
      student2.setClasses(classes);
        
      Set<Student> students=new HashSet<Student>();
      students.add(student1);
      students.add(student2);
        
      classes.setStudents(students);
      //同样能正确保存.sql语句如下:
      //如果<set>标签中有inverse="true",cascade="save-update":
      //Hibernate: insert into sxt_hibernate_class (name, id) values (?, ?)
      //Hibernate: insert into sxt_hibernate_student (name, class_id, id) values (?, ?, ?)
      //Hibernate: insert into sxt_hibernate_student (name, class_id, id) values (?, ?, ?)
      //这种情况student的class_id也有了,因为在插入student时,由student来维护了关系,而它引用的class已经是持久化的了.
        
      //存储过程是这样的:存classes时,由于有cascade="save-update",它会先触发存储student;    
      // 而在存储student时,inverse="true"指明了由它来维护关联关系,所以他要先存主表class,再回来存副表student
      session.save(classes);*/

       /**
        * 小结:情况1是我们提倡的;
        *         情况2.1虽然也能实现正确插入,但是效率低;
        *         情况2.2显然是错误的;
        *         情况3虽然也能实现,并且效率也不低,但是编程上比较麻烦.
        */

        
       /**
        * 测试加载数据
        */

      Student student=(Student)session.get(Student. class, 3);
      System.out.println(student);
      System.out.println(student.getClasses());
      t.commit();
    } catch (HibernateException e) {
      e.printStackTrace();
      t.rollback();
    } finally {
      HibernateUtils.closeSession(session);
    }
  }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值