JAVAEE

JAVAEE框架学习——Hibernate——一对多|多对多关联

2018-05-21  本文已影响18人  So_ProbuING

表关系的分析

数据库中多表之间存在着三种关系:


表关系

表与表的三种关系:

一对多|多对一

建表原则:在多的一方创建外键指向一的一方的主键

一对多

表中的表达

表中表达

实体中的表达

实体中的表达

orm元数据表达

 <!--表示多对一-->
        <many-to-one name="customer"
                     column="lkm_cust_id"
                     class="Customer">

        </many-to-one>

这里的这个配置表示的是:当前的这个配置对象存在多对一的情况,其中name表示实体中多对一的一的名字,column表示外键的列名 class表示的是多个对一个的一的实体类名

 <!--配置集合 一对多的关系-->
        <set name="linkMens">
            <!--指定外键列名-->
            <key column="lkm_cust_id"></key>
            <!--指定一对多还是多对多
                class指定是与哪个类型一对多
            -->
            <one-to-many class="LinkMan"/>
        </set>

这里的这个配置表示的是:当前的这个配置对象存在多对一的情况,其中name表示实体中多个的set集合,key column表示外键的列名 class表示的是一对多的多的实体类名

 /**
     *保存客户以及客户下的联系人
     */
    @Test
    public void fun1() {
        //获得session
        Session session = HibernateUtils.openSession();
        //开启事物
        Transaction tx = session.beginTransaction();
        //----------------------------
        //操作数据
        Customer customer = new Customer();
        customer.setCust_name("xxx");
        LinkMan lm1 = new LinkMan();
        lm1.setLkm_name("aaa1");
        LinkMan lm2 = new LinkMan();
        lm2.setLkm_name("aaa2");
        //表达一对多关系 客户下有多个联系人
        customer.getLinkMens().add(lm1);
        customer.getLinkMens().add(lm2);
        //表达多对一 联系人属于哪个客户
        lm1.setCustomer(customer);
        lm2.setCustomer(customer);

        //瞬时状态对象---->持久化状态
        session.save(customer);
        session.save(lm1);
        session.save(lm2);
        //----------------------------
        //提交事物
        tx.commit();
        //关闭资源
        session.close();
    }
/**
     * 为客户添加联系人
     */
    @Test
    public void fun2() {
        //获得session
        Session session = HibernateUtils.openSession();
        //开启事物
        Transaction tx = session.beginTransaction();
        //----------------------------
        //操作数据
        //获得要操作的客户对象
        Customer customer = session.get(Customer.class, 1l);

        //创建联系人
        LinkMan lm1 = new LinkMan();
        //将联系人添加到客户,将客户设置到联系人中
        customer.getLinkMens().add(lm1);
        lm1.setCustomer(customer);
        //执行保存
        session.save(customer);
        session.save(lm1);
        //----------------------------
        //提交事物
        tx.commit();
        //关闭资源
        session.close();
    }
 /**
     * 从客户中删除某个联系人
     */
    @Test
    public void fun3() {
        //获得session
        Session session = HibernateUtils.openSession();
        //开启事物
        Transaction tx = session.beginTransaction();
        //----------------------------
        //操作数据
        //获得客户
        Customer c = session.get(Customer.class, 1l);
        LinkMan lm = session.get(LinkMan.class, 3l);
        //获得客户的联系人
        //将要移除的联系人从客户的联系人集合中移除
        c.getLinkMens().remove(lm);
        //清空联系人的客户
        lm.setCustomer(null);
        //----------------------------
        //提交事物
        tx.commit();
        //关闭资源
        session.close();
    }

上面的代码再删除某个联系人时由于数据都是查询出来的,都是出于持久态的对象,所以再事务进行提交时Hibernate会查看数据是否发生变化,发生变化后会将数据更新,所以不需要执行session.save()方法进行保存数据

操作进阶

在上面的操作中,我们在操作保存客户的联系人的时候,我们需要执行多条保存的代码,这样显然很麻烦,我们希望再保存客户的时候,将客户的联系人也一起保存。所以我们需要进行一些别的配置

 <!--级联操作:cascade
                save-update:级联保存更新
                delete:级联删除
                all: save-update delete 级联保存更新和级联删除
            级联操作:简化操作

        -->
        <set name="linkMens" cascade="all">
            <!--配置集合 一对多的关系-->
            <!--指定外键列名-->
            <key column="lkm_cust_id"></key>
            <!--指定一对多还是多对多
                class指定是与哪个类型一对多
            -->
            <one-to-many class="LinkMan"/>

        </set>

级联操作应用在一对多的多的时候,也可以实现保存联系人的时候将客户保存

 <!--表示多对一-->
        <many-to-one name="customer"
                     column="lkm_cust_id"
                     class="Customer"
                     cascade="all"
        >

操作代码

/**
     * 级联操作 保存联系人 级联保存客户
     */
    @Test
    public void fun5() {
        //获得session
        Session session = HibernateUtils.openSession();
        //开启事物
        Transaction tx = session.beginTransaction();
        //----------------------------
        //操作数据
        //创建客户
        Customer customer = new Customer();
        customer.setCust_name("google company");

        //创建联系人
        LinkMan lm = new LinkMan();
        lm.setLkm_name("劈柴哥");
        //为客户添加联系人
        customer.getLinkMens().add(lm);
        //为联系人指定客户
        lm.setCustomer(customer);
        //保存客户----> 只保存联系人 通过级联操作保存客户
        session.saveOrUpdate(lm);

        //----------------------------
        //提交事物
        tx.commit();
        //关闭资源
        session.close();
    }

在平时开发中,建议使用save-update 不建议使用delete 级联删除会删除相关的所有数据

 <!--
            inverse属性:配置关系是否维护
            配置当前的Customer是否维护与LinkMan的关系
            inverse true 的意思就是将关系维护的工作完全交给对方 作为配置方不进行维护关系
                    * 不维护关系无法在删除的时候将外键置为空
                    false(默认值) 意思是将关系维护的工作由配置方来维护
                    原则:无论关系方如何放弃关系,总有一方必须要维护关系
                    一对多关系当中,也只能是一的一方放弃维护,多的一方不能放弃
                
        -->
        <set name="linkMens" inverse="true">
            <key column="lkm_cust_id"></key>
                class指定是与哪个类型一对多   
            <one-to-many class="LinkMan"/>
        </set>

tips:在开发中的删除数据,结合inverse 和cascade 实现不同的数据删除策略。以这个demo为例,一个客户可以由多个联系人。在这种情况下 相当于客户和联系人维持着某种关系。我们在有需求删除客户的时候对联系人的删除有两种。
第一种:删除Customer的时候,将LinkMan的外键置为空,LinkMan数据保留
这种情况下,如果Customer不维护数据的话是无法操作LinkMan的外键的,所以在这种情况下我们需要让Customer inverse配置为false 让customer维护关系,在这种情况下删除Customer的时候会删除LinkMan的关系。
第二种:删除Customer的时候,级联操作将LinkMan的数据删除。
在这种情况下,将Customer inverse设置为true 并且将cascade指定为delete 这样在删除Customer的同时就会删除LinkMan子表中的数据。

多对多关联关系映射操作

建表原则:创建一个中间表,中间表中至少两个字段作为外键分别指向多对多双方的主键

多对多

表中关系表达

表中表达

实体中的表达

实体中的表达

orm元数据表达

  <set name="roles" table="sys_user_role">
            <!--
                key标签
                    column:当前对象在中间表中的外键名称
            -->
            <key column="user_id"></key>
            <!--
                many-to-many标签:
                class:关联另一方的类的全类名
                column 关联的另一方在中间表的外键名称
            -->
            <many-to-many class="Role" column="role_id"></many-to-many>
        </set>
  <!--Role多对多配置-->
        <set name="users" table="sys_user_role">
            <key column="role_id"/>
            <many-to-many class="User"
                          column="user_id"/>
        </set>

多对多操作

我们使用案例:保存员工以及角色

在多对多关系中一定要有一方放弃关系的维护,否则会出现主键重复错误
放弃关系维护在配置文件中使用 inverse=“true” 表示放弃操作

  <!-- inverse 属性 使得一方放弃维护外键关系-->
        <set name="users" table="sys_user_role" inverse="true">
            <key column="role_id"/>
            <many-to-many class="User"
                          column="user_id"/>
        </set>
 //从工厂获得session
        Session session = HibernateUtil.openSession();
        //开启事物
        Transaction tx = session.beginTransaction();
        //操作数据
        //-------------------------------
        //创建两个User
        User user1 = new User();
        User user2 = new User();
        user1.setUser_name("blackman");
        user2.setUser_name("whiteman");

        //创建两个role
        Role role1 = new Role();
        Role role2 = new Role();
        Role role3 = new Role();
        role1.setRole_name("vp");
        role2.setRole_name("cto");
        role3.setRole_name("security");


        //用户表达关系
        user1.getRoles().add(role1);
        user1.getRoles().add(role2);
        user2.getRoles().add(role1);
        user2.getRoles().add(role3);
        //角色表达关系
        role1.getUsers().add(user1);
        role1.getUsers().add(user2);
        role2.getUsers().add(user1);
        role3.getUsers().add(user2);
        //保存到数据库
        session.save(user1);
        session.save(user2);
        session.save(role1);
        session.save(role2);
        session.save(role3);
        //-------------------------------
        //提交事务
        tx.commit();
        //关闭资源
        session.close();

 @Test
    /**
     * 添加角色到某个用户中
     */
    public void addRoleToUser() {
        Session session = HibernateUtil.openSession();
        Transaction tx = session.beginTransaction();
        //操作
        //------------
        //获得要添加的用户
        User user = session.get(User.class, 1l);
        //创建公关角色
        Role role = new Role();
        role.setRole_name("公关");
        //将角色添加到用户
        user.getRoles().add(role);
        //将角色转换为持久化
        session.save(role);
        //------------
        tx.commit();
        session.close();
    }

/**
* 从指定角色删除
*/
  @Test
    public void delRoleFromUser(){
        //获取session
        Session session = HibernateUtil.openSession();
        //开启事物
        Transaction tx = session.beginTransaction();
        //操作数据
        //-------------
        //获得要删除的数据
        User user = session.get(User.class, 3l);
        //获得要删除的角色数据
        Role role = session.get(Role.class, 7l);
        user.getRoles().remove(role);
        //-------------
        //提交事务
        tx.commit();
        //关闭资源
        session.close();
    }


进阶操作

        <set name="roles" table="sys_user_role" cascade="save-update">

可以进行级联保存 上面的操作代码不再需要

session.save(role)

一对一

上一篇下一篇

猜你喜欢

热点阅读