hibernate多表操作之一对多的双向关联

时间:2023-02-03 11:57:10
实例:Classes与Student    一对多,相比一对多的单项关联,这回,能在Student里面也能找到学生
    持久化类:Classes 班级,一个班级有多个学生,通过集合来建立关系
 private Long cid; //标示符属性
 private String name;  //一般属性
 private String description;
 
 private Set<Student> students;  //
关联对象

   持久化类:Student 学生
public class Student implements Serializable{
 private Long sid;
 private String name;
 private String description;
 
private Classes classes;//关联对象
   映射文件:Classes.hbm.xml    这里建立的student表中的外键cid,作用是:指的是通过class联系student拼接的sql语句,class.getStudents()
<hibernate-mapping>
 <class name="com.itheima12.hibernate.domain.Classes" lazy="false">
  <cache usage="read-write"/>
  <id name="cid" length="5">
   <generator class="increment"></generator>
  </id>
  <property name="description" length="50"></property>
  <property name="name" length="20"></property>
  <!--
   set元素针对的就是Classes类中的Set属性
   cascade  级联操作
      null  默认值
      save-update
          在保存classes对象的时候,针对student进行保存或者更新的操作
          在更新classes对象的时候,针对student进行保存或者更新的操作
      all
      delete
   inverse  关系操作
      default:classes维护classes与student之间的关系
      true:   classes不维护classes与student之间的关系
      false:  classes维护classes与student之间的关系
   -->
  <set name="students" cascade="save-update" inverse="true" lazy="extra">
   <cache usage="read-write"/>
   <!--
    外键
        告诉hibernate,通过cid就可以建立classes与student之间的关联
    -->
   <key>
    <column name="cid"></column>
   </key>
   <!--
    告诉hibernate,Classes类中的set集合中存放的是哪个元素
    -->
   <one-to-many class="com.itheima12.hibernate.domain.Student"/>
  </set>
 </class>
</hibernate-mapping>

   映射文件:Student.hbm.xml(相比单项,这里指定了student与classes 类是many-to-one的关系)   上面已经指定student表中的外键,为什么这里还需要指定?   这里指定外键,是为了通过学生联系班级,student.getClasses(),在这里因为它是双向的,比如通过班级找学生,就要看班级的映射文件 ,   通过学生找班级,就要看学生的映射文件,在学生的映射文件中有了外键,就可以之间利用外键拼接sql查询班级的sql语句   这里再次指定student表的外键,不影响表的结构,这里这么做,方便hibernate客户端通过学生操作班级。即:通过保存学生(多的一方),级联保存班级,但是注意sql语句是怎么执行


<hibernate-mapping>
<class name="com.itheima12.hibernate.domain.Student">
<id name="sid" length="5">
<generator class="increment"></generator>
</id>
<property name="description" length="50"></property>
<property name="name" length="20"></property>
<!--
外键
column
-->
<many-to-one name="classes" column="cid" class="com.itheima12.hibernate.domain.Classes"cascade="save-update"></many-to-one>
</class>
</hibernate-mapping>


  客户端的操作   对于在多的方级联保存一的一方,虽然先保存学生,数据库把提供外键的classess先插入数据库,   而通过班级保存学生最后是通过update学生表的形式,最后把外键更新到学生表里面  
/**hibernate输出的sql语句
  * Hibernate:
      select max(sid) from Student
  Hibernate:
      select  max(cid)  from Classes
  Hibernate:
      insert into Classes (description, name, cid) values(?, ?, ?)
  Hibernate:
             外键直接插入进去了(session.save保存的对象,发出的sql语句越少,越适合关系维护)
      insert into Student (description, name,cid, sid) values (?, ?, ?, ?)
  */
 @Test
 public void testSaveStudent_Cascade_Save_Classes(){
  Session session = sessionFactory.openSession();
  Transaction transaction = session.beginTransaction();
  Student student = new Student();
  student.setName("asfd");
  
  Classes classes = new Classes();
  classes.setName("12期");
  
  //创建班级与学生之间的关联
  student.setClasses(classes);  //通过学生建立的关联
  
  session.save(student);
  transaction.commit();
  session.close();
 }

  操作两张表,并把数据保存到数据库中
      在相应的类的映射文件设置级联保存的情况下,客户端(service层)该如何做? 关联对象       1、通过保存学生(多),级联保存班级             注意:根据hibernate打印的sql语句,即便session.save(student),还是先insert的是Classes,因为它提供student外键            客户端建立关联,把一个班级对象放入到自己类的属性private Classes classes;//关联对象       2、通过保存班级(一),级联保存学生            把已有的学生对象加入到Classes的 private Set<Student> students;  //关联对象