• Hibernate(五)之一对多&多对一映射关系


    既然我们讲到了一对多和多对一关系,必然要提到多表设计的问题。在开发中,前期需要进行需求分析,希求分析提供E-R图,根据ER图编写表结构。

    我们知道表之间关系存在三种:

    一对多&多对一:1表(主表)必须主键 和 多表(从表)必须外键,主表的主键 与 从表外键 形成主外键关系

    多对多:提供中间表(从表),提供2个字段(外键)分别对应两个主表。

     

    一对一

     

    下面演示的是一对多&多对一的关系,和上面写的那样使用Customer和Order之间的关系来举例子。

    一、实现类

      1.Customer.java

        

      2.Order.java

        

    二、配置文件

    复制代码
    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE hibernate-mapping PUBLIC 
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
    <hibernate-mapping package="com.jxlg.domain">
        <class name="Customer" table="t_customer">
            <id name="id" column="id">
                <generator class="native"></generator>
            </id>
            <property name="name" column="name" type="string"></property>
            <!-- 
            一对多:一个客户(当前客户) 拥有 【多个订单】
                表达一对多关系中的集合
                name:集合的属性名称
                inserse:是否将关系的维护反转给对方。默认值:false
                        true:在Customer中放弃维护外键关系。
             -->
             <set name="orders" inverse="true">
                 <!-- 
                     key:用来描述外键
                     column:外键的值
                  -->
                 <key column="cid"></key>
                 <!--one-to-many 表达,Customer与orders的关系是一对多
                     class:表达关联另一方的完整类名
                  -->
                 <one-to-many class="Order"/>
             </set>
        </class>
    </hibernate-mapping>
    复制代码
    复制代码
    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE hibernate-mapping PUBLIC 
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
    <hibernate-mapping package="com.jxlg.domain">
        <class name="Order" table="t_order">
            <id name="id" column="id">
                <generator class="native"></generator>
            </id>
            <property name="name" column="name" type="string"></property>
            <!-- 多对一:多个订单属于【一个客户】 
            表达多对一的关系
                name:引用的属性名称
                column:外键的列名
                class:我引用的Order的完整类名
             -->
             <many-to-one name="customer" column="cid" class="Customer"></many-to-one>
        </class>
    </hibernate-mapping>
    复制代码

    三、一对多的操作

    3.1、一对多关系的基本操作

    复制代码
    package com.jxlg.onetomany;
    
    import static org.junit.Assert.*;
    
    import java.util.Set;
    
    import org.hibernate.Session;
    import org.hibernate.Transaction;
    import org.junit.Test;
    
    import com.jxlg.domain.Customer;
    import com.jxlg.domain.Order;
    import com.jxlg.util.HibernateUtils;
    
    //测试一对多关系
    public class Demo1 {
    
        
        //一对多关系的保存操作
        //共打印5条语句
        //前三条insert=》用来保存对象,维护外键
        //后两条update =》用来维护外键
        //解决:单纯的指定   关系由一方来维护,另一方不维护关系。
        //注意:外键维护的放弃,只能由非外键所在对象放弃。
        //Customer inverse=true
        //只打印三天语句 =》外键由order自己来维护
        @Test
        public void test1() {
            Session session = HibernateUtils.openSession();
            Transaction ts = session.beginTransaction();
            //----------------------------------------
                Customer cus = new Customer();
                cus.setName("jerry");
                
                Order or1 = new Order();
                or1.setName("酱油");
                Order or2 = new Order();
                or2.setName("练习本");
                
                //cus.getOrders().add(or1);//维护关系
                //cus.getOrders().add(or2);//维护关系
                
                or1.setCustomer(cus);//维护关系
                or2.setCustomer(cus);//维护关系
                
                session.save(cus);
                session.save(or1);
                session.save(or2);
            //----------------------------------------
            ts.commit();
            session.close();
        }
        
        //多表关系 =》删除
        //删除  用户时,会先移除Customer中引用的外键,然后再删除Customer
        //结论:维护一方的对象时,会自动维护另一方的关系。
        //Customer 的inverse属性:true
        //会报错=》Customer不负责维护外键,直接删除Customer会导致,Order引用了无效的id,违反了外键约束。
        @Test
        public void test2() {
            Session session = HibernateUtils.openSession();
            Transaction ts = session.beginTransaction();
            //----------------------------------------
                Customer c = (Customer) session.get(Customer.class, 5);
                
                //解决 :Customer 的inverse属性:true
                Set<Order> set = c.getOrders();
                for(Order o :set){
                    o.setCustomer(null);//设置订单不属于任何Customer
                }
                session.delete(c);
            //----------------------------------------
            ts.commit();
            session.close();
        }
        //什么时候配置inverse属性?
        //主要看业务,如果一的一方经常需要维护外键 = 在1的一方不要配置inverse属性。
    
    }
    复制代码

      3.2、级联操作

        在fun1中

          

    测试一:cascade的值为:save-update、delete

    复制代码
    /测试 一对多关系
    public class Demo2 {
        @Test
        //增
        //我们希望在保存Customer时,自动将未保存的Orders当中的Order保存
        //cascade: save-update
        public void fun1(){
            Session session = HibernateUtils.openSession();
            session.beginTransaction();
            //------------------------------------------------
            Customer c = new Customer();
            c.setName("tom");
            
            Order o1 = new Order();
            o1.setName("肥皂");
            
            Order o2 = new Order();
            o2.setName("蜡烛");
            
            c.getOrders().add(o1);//维护关系
            c.getOrders().add(o2); //维护关系
            
            
            /*
            o1.setCustomer(c);//维护关系
            o2.setCustomer(c);//维护关系
             */        
            
            session.save(c);//保存对象
            //session.save(o1);//保存对象
            //session.save(o2);//保存对象
            
            //------------------------------------------------
            session.getTransaction().commit();
            session.close(); // 游离状态
        }
        @Test
        //增
        //我们希望在保存Customer时,自动将未保存的Orders当中的Order保存
        //cascade: save-update
        public void fun2(){
            Session session = HibernateUtils.openSession();
            session.beginTransaction();
            //------------------------------------------------
            
            Customer c = (Customer) session.get(Customer.class, 8);//1条 select
            
            for(Order o :c.getOrders()){ // 1条 select
                o.setName("哇哈哈"); // 修改订单
            }
            
            //------------------------------------------------
            session.getTransaction().commit();//因为设置级联修改,自动将订单的修改保存到数据
                                              //update语句
            session.close(); // 游离状态
        }
        
        @Test
        //cascade: delete
        //删除Customer时 ,会将Customer下的订单一并删除
        //inverse : false   6条sql语句   
        //inverse : true    5条sql语句 比上面少一条维护外键
                
        public void fun3(){
            Session session = HibernateUtils.openSession();
            session.beginTransaction();
            //------------------------------------------------
            
            Customer c = (Customer) session.get(Customer.class, 7);//1条 select
            
            
            session.delete(c);//删除Customer
                             // 删除两个Order
            
            //------------------------------------------------
            session.getTransaction().commit();
                                              
            session.close(); // 游离状态
        }
        
        @Test
        //cascade: delete
        //操作的两方cascade值都为delete
        //需要注意: 千万不要在两方都配置 级联删除. 删除任何一方,会导致整个关系链对象全部删除.
        public void fun4(){
            Session session = HibernateUtils.openSession();
            session.beginTransaction();
            //------------------------------------------------
            Order o  = (Order) session.get(Order.class, 9);//select
            
            session.delete(o);//delete删除当前order
            
                                //找到所有关联的Customer删除 select
                                // delete Customer
                                // Customer配置了级联删除=> select 找下面的order
                                // 删除所有Order
                                //删除Customer
            
            //------------------------------------------------
            session.getTransaction().commit();
                                              
            session.close(); // 游离状态
        }
    }
    复制代码

     测试二:cascade的值为:delete-orphan 

    复制代码
    public class Demo3 {
        @Test
        //inverse:false
        //cascade: delete-orphan 孤儿删除 => 当没有任何外键引用Order时,order 会被删除
        public void fun1(){
            Session session = HibernateUtils.openSession();
            session.beginTransaction();
            //------------------------------------------------
                Customer c = (Customer) session.get(Customer.class, 9);
                Iterator<Order> it = c.getOrders().iterator();
                //注意: 删除Customer下的订单时,不能使用 c.setOrders(null); c.setOrders(new HashSet());
                while(it.hasNext()){ // 遍历Customer下的订单,并将订单删除 => 维护关系
                    it.next();
                    it.remove();
                }
                //------------------------------------------------
                session.getTransaction().commit();
                session.close(); // 游离状态
        }
        
        
    } 
    复制代码

      测试三: cascade的值为:all-delete-orphan

    复制代码
    /测试 一对多关系
    public class Demo4 {
        @Test
        //cascade: all-delete-orphan => 相当于配置 save-update,delete,delete-orphan
        public void fun1(){
            Session session = HibernateUtils.openSession();
            session.beginTransaction();
            //------------------------------------------------
            Customer c = new Customer();
            c.setName("tom");
            
            Order o1 = new Order();
            o1.setName("肥皂");
            
            Order o2 = new Order();
            o2.setName("蜡烛");
            
            c.getOrders().add(o1);//维护关系
            c.getOrders().add(o2); //维护关系
            
            session.save(c);
            //------------------------------------------------
                session.getTransaction().commit();
                session.close(); // 游离状态
        }
        @Test
        //cascade: all-delete-orphan => 相当于配置 save-update,delete,delete-orphan
        public void fun2(){
            Session session = HibernateUtils.openSession();
            session.beginTransaction();
            //------------------------------------------------
            Customer c = (Customer) session.get(Customer.class, 10);
            session.delete(c);
            //------------------------------------------------
                session.getTransaction().commit();
                session.close(); // 游离状态
        }
        
        
        @Test
        //cascade: all-delete-orphan => 相当于配置 save-update,delete,delete-orphan
        public void fun3(){
            Session session = HibernateUtils.openSession();
            session.beginTransaction();
            //------------------------------------------------
            Customer c = (Customer) session.get(Customer.class, 12);
    
            Iterator<Order> it = c.getOrders().iterator();
            
            while(it.hasNext()){ // 遍历Customer下的订单,并将订单删除 => 维护关系
                it.next();
                it.remove();
            }
            
            //------------------------------------------------
                session.getTransaction().commit();
                session.close(); // 游离状态
        }
    }
    复制代码

       联级操作总结:

            save-update:A保存,同时保存B

            delete:删除A,同时删除B,AB都不存在

            delete-orphan:孤儿删除,解除关系,同时将B删除,A存在的。

            如果需要配置多项,使用逗号分隔。<set cascade="save-update,delete">

            all : save-update 和 delete 整合

            all-delete-orphan : 三个整合

  • 相关阅读:
    完美图解教程 Linux环境VNC服务安装、配置与使用
    c语言中<stdbool.h>的使用
    UNIX文件结构(转自UNIX/AIX操作系统基础教程)
    umask
    在AIX环境为Oracle表空间增加裸设备(逻辑卷)
    面的面积大小合线的长度的判断。
    不用新浪博客了。以后的日常感悟也在这里写了, 新浪太烂了。 (感叹也没用,什么都写不出来。 )
    轴心工具的做法。
    选择因素随机的判断。
    上面发的那个完整版变量还有问题,难道我不是用英文输入法, 电脑不说谎 ,看来我是大意了。下面是最终版。
  • 原文地址:https://www.cnblogs.com/Jeely/p/11226465.html
Copyright © 2020-2023  润新知