zoukankan      html  css  js  c++  java
  • 06章 映射一对多双向关联关系、以及cascade、inverse属性

    当类与类之间建立了关联,就可以方便的从一个对象导航到另一个对象。或者通过集合导航到一组对象。例如:

    对于给定的Emp对象,如果想获得与它关联的Dept对象,只要调用如下方法

    Dept dept=emp.getDept(); //从Emp对象导航到关联的Dept对象 

    以Dept(部门)类和Emp(员工)类为例:

    一、配置双向一对多关联

    需在Dept类中增加一个集合类型的emps属性

    复制代码
        private Set<Emp> emps=new HashSet<Emp>();
    
        public Set<Emp> getEmps() {
        return emps;
    }
    
        public void setEmps(Set<Emp> emps) {
        this.emps = emps;
    复制代码

    如何在映射文件中映射集合类型的emps属性。由于在Dept表中没有直接与emps属性对应的字段。因此不能用<property>元素来映射emps属性,而要使用<set>元素:

     <set name="emps">
            <key column="deptNo"></key>  <!-- 多的一方 emp外键 -->
            <one-to-many class="Emp" />
          </set>

    解析:

    <set>元素的name属性:设定持久化类的属性名。此处为Dept类的emps属性。

    <set>元素还包含两个子元素:

    ①<key>元素:column属性设定与所关联的持久化类对应的表的外键

    ②<one-to-many>元素:class属性设定与所关联的持久化类

    hibernate根据以上映射代码获得以下信息:

    ①<set>元素表明Dept类的emps属性为java.util.Set集合类型

    ②<one-to-many>子元素表明emps集合中存放的是一组Emp对象

    ③<key>子元素表明EMP表通过外键DEPTNO参照Dept表

    Dept.hbm.xml代码:

    复制代码
    <?xml version="1.0"?>
    <!DOCTYPE hibernate-mapping PUBLIC 
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
    <hibernate-mapping package="cn.happy.onetomanydouble">
       <class name="Dept" table="DEPT">
          <id name="deptNo">
            <generator class="sequence">
              <param name="sequence">SEQ_NUM</param>
            </generator>
          </id> 
          <property name="deptName"/>
          
          <!-- 一对多一个配置,一个部门有N个员工 -->
          <!--
             inverse="false"  主动方   维护关联关系
             
              inverse="true"  不维护关联关系(不干扰Emp的外键生成)
           -->
          <set name="emps" cascade="save-update">
            <key column="deptNo"></key>  <!-- 多的一方 emp外键 -->
            <one-to-many class="Emp" />
          </set>
          
       </class>
    </hibernate-mapping>
    复制代码

    Emp.hbm.xml:

    复制代码
    <?xml version="1.0"?>
    <!DOCTYPE hibernate-mapping PUBLIC 
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
    <hibernate-mapping package="cn.happy.onetomanydouble">
       <class name="Emp" table="EMP">
          <id name="empId">
            <generator class="sequence">
              <param name="sequence">SEQ_NUM</param>
            </generator>
          </id> 
          <property name="empName" type="string"/>
          
          <!-- 植入一个Dept对象 : 多对一-->
          <many-to-one name="dept" class="Dept" column="deptNo"></many-to-one>
       </class>
    </hibernate-mapping>
    复制代码

    进而编写测试类:Test 即可拿到deptNo为1的员工姓名

    复制代码
    public class Test2 {
    
        Session session;
        Transaction tx; 
    
        @After
        public void afterTest(){
            tx.commit();
            HibernateUtil.CloseSession();
        }
    
        @Before
        public void initData(){
            session=HibernateUtil.getSession();
            tx=session.beginTransaction();
        }
        
        /*
         * 一对多双向关联测试
         */
        @Test
        public void oneToManyDoubleTest(){
    
            //获取员工集合
            Dept dept=(Dept)session.load(Dept.class,1);
             Set<Emp> emps =dept.getEmps();
            for (Emp emp : emps) {
                System.out.println(emp.getEmpName());
            }
        }
    复制代码

    二、cascade属性

     none:当Session操纵当前对象时,忽略其他关联的对象。它是cascade属性的默认值.

     Save-update:当通过Session的save()、update()及saveOrUpdate()方法来保存或更新当前对象时,级联保存所有关联的新建的瞬时状态的对象,并且级联更新所有关联的游离状态的对象。

     Delete:当通过Session的delete()方法删除当前对象时,会级联删除所有关联的对象。

    当通过Session的delete()方法删除当前对象时,会级联删除所有关联的对象。

     All:包含save-update,delete的行为。

    解析:

    级联也就是说当我们保存持久化对象A的时候自动帮我们保存持久化对象B。

    问题:cascade属性写在什么位置?

    注:一对一或者多对一的时候,直接写在标签上,其他的写在set标签上。

    如何实现添加部门的同时自动添加员工?

    解析:可以使用cascade(级联)方式

    Test:双向关联  通过add()将新建的员工对象添加部门下

    复制代码
    public class Test3 {
        
        Session session;
        Transaction tx; 
    
        @After
        public void afterTest(){
            tx.commit();
            HibernateUtil.CloseSession();
        }
    
        @Before
        public void initData(){
            session=HibernateUtil.getSession();
            tx=session.beginTransaction();
        }
        
        /*
         *cascade
         */
        @Test
        public void oneTest(){
        
            
            //构建一个部门
            Dept dept=new Dept();
            dept.setDeptName("财务部");
            
            //构建一个员工
            Emp emp=new Emp();
            emp.setEmpName("张三");
            
            //指定员工隶属的部门
            emp.setDept(dept);
            
    
            // setXXX 部门下的员工
            dept.getEmps().add(emp);
            
            //save
            
            session.save(dept);
            session.save(emp);
        }
        
        }
    复制代码

    三、<Set>元素下的inverse属性(反转)

    inverse属性指定了关联关系中的方向。

    inverse设置为false,则为主动方,由主动方负责维护关联关系,默认是false 。

    注意:inverse 决定是否把对对象中集合的改动反映到数据库中,所以inverse只对集合起作用,也就是只对one-to-many或many-to-many有效(因为只有这两种关联关系包含集合,而one-to-one和many-to-one只含有关系对方的一个引用)。

    代码同理:

    说明:如果我既给员工指定了自己所属的部门,又将员工添加到部门集合中。那么这个时候reverse不设置,生成以下sql

    inverse设置为true,不负责维护关联关系

    第二条insert语句已经在员工表中指定了自己所属的部分,没有必要再向数据库发送一条update指令。

    将inverse设置成true后,生成的语句如下图所示。

  • 相关阅读:
    Celery(异步任务,定时任务,周期任务)
    SQLAlchemy的应用创建
    SQLAlchemy多对多
    SQLAlchemy
    app开发-2
    app开发-3
    app开发-1
    MongoDB-pymongo
    MongoDB-增删改查
    MongoDB-数据类型
  • 原文地址:https://www.cnblogs.com/hr1997/p/5833249.html
Copyright © 2011-2022 走看看