(八)Hibernate的一对多关联关系

一、概述

例如,以客户(Customer)和订单(Order)为例,一个客户能有多个订单,一个订单只能有一个客户。 

从Customer到Order是一对多关联,在java类中的面向对象设计应该一个Customer对象包含多个Order对象,因此应该定义一个集合,来包含所有的Order对象。  

从Order到Customer是多对一关联,在java类中设计每个Order对象需要关联一个Customer对象,因此Order类中应该定义一个Cutomer类型的属性,来引用关联的customer对象。

但是在关系数据库中,只存在主外键参照关系来表达两者的关联。

  

二、实例

(1)先创建两个实体类 Customer和Order

  public class Customer {
                    private Integer id;
                    private String name;
                    private Set <Order> orders=new HashSet<Order>();
                    public Integer getId() {
                        return id;
                    }
                    public void setId(Integer id) {
                        this.id = id;
                    }
                    public String getName() {
                        return name;
                    }
                    public void setName(String name) {
                        this.name = name;
                    }
                    public Set getOrders() {
                        return orders;
                    }
                    public void setOrders(Set orders) {
                        this.orders = orders;
                    }

            } 

            public class Order {
                private Integer id;
                private String name;
                private Customer customer;
                public Integer getId() {
                    return id;
                }
                public void setId(Integer id) {
                    this.id = id;
                }
                public String getName() {
                    return name;
                }
                public void setName(String name) {
                    this.name = name;
                }
                public Customer getCustomer() {
                    return customer;
                }
                public void setCustomer(Customer customer) {
                    this.customer = customer;
                }

            }

 (2)实体类写好了,使用Hibernate映射文件来映射关系 

创建Customer.hbm.xml:

             <hibernate-mapping >
                <!--指定实体类和表的映射关系-->
                <class name="com.cad.domain.Customer" table="customer">
                    <id name="id" column="id">
                        <generator class="native"></generator>
                    </id>
                    <property name="name" column="name"></property>
                    <!--使用<set>元素来映射set集合类型-->
                    <!--
                        name:持久化类中的属性名
                    -->
                    <set name="orders">
                        <!--<key>元素设定所关联的持久化类对应的表的外键-->
                        <!--<one-to-many>元素设定关联的持久化类-->
                        <key column="cid"/>
                        <one-to-many class="com.cad.domain.Order"/>
                    </set>
                </class>
             </hibernate-mapping>  

            Hibernate根据映射文件获得以下信息
            -<set>元素表明Customer类中的orders属性为java.util.Set集合
            -<one-to-many>元素表明orders集合中存放的是一组order对象
            -<key>元素表明orders表通过外键cid关联customer表

  

创建Order.hbm.xml

            <hibernate-mapping >
                <class name="com.cad.domain.Order" table="order">
                    <id name="id" column="id">
                        <generator class="native"></generator>
                    </id>
                    <property name="name" column="name"></property>
                    <!--<many-to-one>元素建立了customer属性和对应表中外键的映射-->
                    <!--
                        name:持久化类中的属性名
                        column:表中的外键
                        class:关键的Customer对象实现类
                    -->
                    <many-to-one name="customer" column="cid" class="com.cad.domain.Customer"></many-to-one>
                </class>
             </hibernate-mapping>

 (3)在hibernate.cfg.xml中配置映射文件

                 <mapping resource="com/cad/domain/Customer.hbm.xml"/>
                  <mapping resource="com/cad/domain/Order.hbm.xml"/>

 (4)测试

                 //添加方法
                    @Test
                    public void test() {
                        //读取配置文件
                        Configuration conf=new Configuration().configure();

                        //根据配置创建factory
                        SessionFactory sessionfactory=conf.buildSessionFactory();
                        session = sessionfactory.openSession();
                         Transaction ts=session.beginTransaction();
                         //创建Customer
                        Customer c=new Customer();
                        c.setName("张三");
                        //创建订单
                        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);
                        ts.commit();
                        session.close();
                        sessionfactory.close();
                    }

                    然后执行,控制台会打印如下语句
                            Hibernate:
                                insert
                                into
                                    customer
                                    (name)
                                values
                                    (?)
                            Hibernate:
                                insert
                                into
                                    orders
                                    (name, cid)
                                values
                                    (?, ?)
                            Hibernate:
                                insert
                                into
                                    orders
                                    (name, cid)
                                values
                                    (?, ?)
                            Hibernate:
                                update
                                    orders
                                set
                                    cid=?
                                where
                                    id=?
                            Hibernate:
                                update
                                    orders
                                set
                                    cid=?
                                where
                                    id=?

  我们来执行删除操作,直接删除Customer,但由于还有Order关联着Customer 会执行成功么?

                            @Test
                            public void test() {
                                //读取配置文件
                                Configuration conf=new Configuration().configure();

                                //根据配置创建factory
                                SessionFactory sessionfactory=conf.buildSessionFactory();
                                session = sessionfactory.openSession();
                                 Transaction ts=session.beginTransaction();
                                 Customer c=session.get(Customer.class, 2);
                                 //删除Customer
                                session.delete(c);

                                ts.commit();
                                session.close();
                                sessionfactory.close();
                            }
                        执行,打印如下语句
                            Hibernate:
                                select
                                    customer0_.id as id1_0_0_,
                                    customer0_.name as name2_0_0_
                                from
                                    customer customer0_
                                where
                                    customer0_.id=?
                            Hibernate:
                                update
                                    orders
                                set
                                    cid=null
                                where
                                    cid=?
                            Hibernate:
                                delete
                                from
                                    customer
                                where
                                    id=? 

        我们会发现Hibernate会自动将Order中的cid设置为null,然后执行删除操作
        我们发现Hibernate还是挺智能的,但这是由inverse属性操控的。

  

三、< set >元素的inverse属性

 

inverse所描述的是对象之间关联关系的维护方式。 inverse属性指定由哪方来维护关联关系。
inverse默认为false,即关联关系由自己控制,若为true,则反转,关联关系由对方控制.
Inverse属性的作用是:是否将对集合对象的修改反映到数据库中。 

在映射一对多的双向关联关系中,应该在"一"方把inverse属性设为true,由对方来维护主键关联关系.

所以上述例子中,inverse默认是false.即Customer维护关联关系,所以Customer会执行两条更新语句来更新Order的cid.
但是我们Order在插入的时候已经插入cid,所以这样会影响性能,我们只需要将Customer的<set>元素的inverse属性改为true即可。 

我们的删除案例中也是,Customer执行删除时,会先去把Order的主键约束解除,然后删除。
我们只需要将Customer的inverse设置为true,然后由对方维护关联关系,我们再进行删除时,就会出现异常,因为有主键约束,我们Customer不再维护关联关系。

四、级联操纵

在实际应用中,对象和对象之间是相互关联的。例如我们的一对多关联关系。 
在关系-对象映射文件中,用于映射持久化类之间关联关系的元素,如 < set>,< many-to-one>,< one-to-many>,都有一个cascade属性,用来指定如何操纵与当前对象关联的其他对象。

    我们先看下面的例子,我们创建一个Customer,再创建两个Order,然后关联
    我们只保存Customer,会抛出org.hibernate.TransientObjectException异常,这是为什么呢?

    这是因为我们的Customer的inverse为false,关联关系由Customer维护。我们保存Customer时,
    会维护Customer中orders中的所有Order的主键,但是Order是临时对象,并没有转变为持久状态,这时候就会抛出异常。

            @Test
            public void test() {
                //读取配置文件
                Configuration conf=new Configuration().configure();

                //根据配置创建factory
                SessionFactory sessionfactory=conf.buildSessionFactory();
                session = sessionfactory.openSession();
                 Transaction ts=session.beginTransaction();
                 Customer c=new Customer();
                 c.setName("jack");
                 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);

                ts.commit();
                session.close();
                sessionfactory.close();
            }

 当Hibernate持久化一个临时对象时,并不会自动持久化所关联的其他临时对象,所以会抛出异常。 
如果我们希望Hibernate持久化对象时自动持久化所关联的其他对象,那么就需要指定cascade属性 

 (1)级联保存和更新

    当我们持久化对象时自动持久化所关联的其他对象。
    把cascade属性设置为save-update ,这时候我们再执行上面的代码就会自动帮我们保存Customer关联的Order对象。

    当cascade属性为save-update时,表明保存或更新当前对象时,会级联保存或更新与它关联的对象。

 (2)级联删除

 如果我们的cascade属性为delete时,我们删除当前对象,会自动删除与之关联的对象。
    慎用这个delete属性。
    例如:我们的Order配置了这个属性,Customer也配置了这个属性,我们删除订单时,因为是级联删除
    所以会查找Customer,删除Customer,但Customer也配置了级联删除,所以会查找所有关联的订单,最后会删除该客户的所有订单和该客户。

 (3)孤儿删除

    如果我们的对象和关联的对象解除关系后,希望自动删除不再关联的对象。
    需要将cascade设置为delete-orphan.

    例如 ,我们设置cascade="delete-orphan"
                     Transaction ts=session.beginTransaction();
                     Customer c=session.get(Customer.class, 7);
                     Order order=(Order) c.getOrders().iterator().next();
                     c.getOrders().remove(order);
                     order.setCustomer(null);
                     ts.commit(); 

    我们解除Customer和Order的关系,Hibernate就会自动删除Order。  

    当cascade的值为all时,是save-update和delete的整合。
    当cascade的值为all-dalete-orphan时,是all和delete-orphan的整合。

  

 

 

 

原文地址:https://www.cnblogs.com/yuexiaoyun/p/9452363.html

时间: 2024-09-28 16:41:31

(八)Hibernate的一对多关联关系的相关文章

hibernate双向一对多关联关系

双向的多对一(一对多)关联关系: 其实这种关联关系就是把单向的多对一和单向的一对多的关联关系的整合.     只是说明一点: 代码:   package qau.edu.ren; import java.util.Date; import org.hibernate.Session; import org.hibernate.Transaction; import org.hibernate.cfg.Configuration; public class Test { public static

[原创]java WEB学习笔记82:Hibernate学习之路---映射 一对多关联关系,配置,CRUD方法测试及注意点

本博客的目的:①总结自己的学习过程,相当于学习笔记 ②将自己的经验分享给大家,相互学习,互相交流,不可商用 内容难免出现问题,欢迎指正,交流,探讨,可以留言,也可以通过以下方式联系. 本人互联网技术爱好者,互联网技术发烧友 微博:伊直都在0221 QQ:951226918 -----------------------------------------------------------------------------------------------------------------

hibernate 一对多关联关系(详细分析)

在领域模型中, 类与类之间最普遍的关系就是关联关系. 在 UML 中, 关联是有方向的. 以 Customer 和 Order 为例: 一个用户能发出多个订单, 而一个订单只能属于一个客户. 从 Order 到 Customer 的关联是多对一关联; 而从 Customer 到 Order 是一对多关联 单向关联 双向关联 单向 n-1 单向 n-1 关联只需从 n 的一端可以访问 1 的一端 域模型: 从 Order 到 Customer 的多对一单向关联需要在Order 类中定义一个 Cus

(转)Hibernate框架基础——一对多关联关系映射

http://blog.csdn.net/yerenyuan_pku/article/details/52746413 上一篇文章Hibernate框架基础——映射集合属性详细讲解的是值类型的集合(即集合元素是普通类型).现在从本文开始我们就要介绍实体类型的集合(即集合元素是另一个实体)了. 一对多关联关系映射 我们还是以一个活生生的例子来详解一对多关联关系映射吧!就以部门和员工的关系为例. 单向关联:仅仅建立从Employee到Department的多对一关联,即仅仅在Employee类中定义

Hibernate中一对多关联的时候hbm.xml文件的配置

body { font-family: 微软雅黑,"Microsoft YaHei", Georgia,Helvetica,Arial,sans-serif,宋体, PMingLiU,serif; font-size: 10.5pt; line-height: 1.5; } html, body { } h1 { font-size:1.5em; font-weight:bold; } h2 { font-size:1.4em; font-weight:bold; } h3 { fon

JPA学习笔记(8)——映射一对多关联关系

一对多关联关系 本文有很多和多对一是一样的,因此不会写得非常具体. 有看不懂的.能够參考JPA学习笔记(7)--映射多对一关联关系 Order实体类 package com.jpa.helloworld2; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.FetchType; import javax.persistence.GeneratedValue; imp

hibernate映射-双向n-n关联关系

(学习记录,错误不足之处,请您耐心指正^_^) hibernate映射-双向n-n关联关系 一.代码示例: {类文件↓} Category.class package com.zit.hibernate.n2n.both; import java.util.HashSet; import java.util.Set; public class Category { private Integer id; private String name; private Set<Item> items

hibernate的一对多

一的一方的配置 多的一方 hibernate的一对多

Hibernate HQL一对多 在一方的查询

首先说一句:是版本的问题! 在多对多或者多对一,从一中查找多中查询某些语句时容易出现 我写的hql为: from Department as d where d.employees.name='Tom'; 运行时出现异常:org.hibernate.QueryException: illegal attempt to dereference collection 是因为:在上面的HQL语句中,Department的关联实体employees是一个集合,而不直接是一个Employee实体. 在Hi