学习笔记之Hibernate_映射关系之一对多映射关系

一、单向一对多映射关系

实体类的创建

1.本例子的 多的一方是Order,一的一方是Customer,一个Customer 可以有很多个Order, 而一个Order只能属于一个Customer。

实体类Customer

package hibernates.entities.n21;

public class Customer {
    private Integer customerId;
    private String customerName;
    public Integer getCustomerId() {
        return customerId;
    }
    public void setCustomerId(Integer customerId) {
        this.customerId = customerId;
    }
    public String getCustomerName() {
        return customerName;
    }
    public void setCustomerName(String customerName) {
        this.customerName = customerName;
    }
    public Customer(String customerName) {
        super();
        this.customerName = customerName;
    }
    public Customer() {
        super();
        // TODO Auto-generated constructor stub
    }
    @Override
    public String toString() {
        return "Customer [customerId=" + customerId + ", customerName=" + customerName + "]";
    }
}

实体类Order

package hibernates.entities.n21;

public class Order {
    private Integer orderId;
    private String orderName;
    private Customer customer;
    public Integer getOrderId() {
        return orderId;
    }
    public void setOrderId(Integer orderId) {
        this.orderId = orderId;
    }
    public String getOrderName() {
        return orderName;
    }
    public void setOrderName(String orderName) {
        this.orderName = orderName;
    }
    public Customer getCustomer() {
        return customer;
    }
    public void setCustomer(Customer customer) {
        this.customer = customer;
    }
    public Order(String orderName, Customer customer) {
        super();
        this.orderName = orderName;
        this.customer = customer;
    }
    public Order() {
        super();
        // TODO Auto-generated constructor stub
    }
    @Override
    public String toString() {
        return "Order [orderId=" + orderId + ", orderName=" + orderName + ", customer=" + customer + "]";
    }
}

编写基础映射文件

Order.hbm.xml的编写:主要是编写<many-to-one>标签

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!-- Generated 2017-11-27 21:13:51 by Hibernate Tools 3.5.0.Final -->
<hibernate-mapping>

    <class name="hibernates.entities.n21.Order" table="ORDERS">

        <id name="orderId" type="java.lang.Integer">
            <column name="ORDERID" />
            <generator class="native" />
        </id>

        <property name="orderName" type="java.lang.String">
            <column name="ORDERNAME" />
        </property>

        <!--
            映射多对一的关联关系。 使用 many-to-one 来映射多对一的关联关系
            name: 多这一端关联的一那一端的属性的名字
            class: 一那一端的属性对应的类名
            column: 一那一端在多的一端对应的数据表中的外键的名字
        -->
        <many-to-one name="customer" class="hibernates.entities.n21.Customer" >
            <column name="CUSTOMER_ID" />
        </many-to-one>

    </class>

</hibernate-mapping>

Customer.hbm.xml的编写

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!-- Generated 2017-11-27 21:13:51 by Hibernate Tools 3.5.0.Final -->
<hibernate-mapping>

    <class name="hibernates.entities.n21.Customer" table="CUSTOMERS">

        <id name="customerId" type="java.lang.Integer">
            <column name="CUSTOMER_ID" />
            <generator class="native" />
        </id>

        <property name="customerName" type="java.lang.String">
            <column name="CUSTOME_RNAME" />
        </property>

    </class>

</hibernate-mapping>

核心配置文件hibernate.cfg.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
        "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
    <session-factory>

        <!-- 配置连接数据库的基本信息 -->
        <property name="connection.username">root</property>
        <property name="connection.password">123456</property>
        <property name="connection.driver_class">com.mysql.jdbc.Driver</property>
        <property name="connection.url">jdbc:mysql:///hibernate</property>

        <!-- 配置 hibernate 的基本信息 -->
        <!-- hibernate 所使用的数据库方言
        <property name="dialect">org.hibernate.dialect.MySQLMyISAMDialect</property>
        <property name="dialect">org.hibernate.dialect.MySQL5InnoDBDialect</property>
        <property name="dialect">org.hibernate.dialect.MySQLDialect</property>        -->

        <!-- 执行操作时是否在控制台打印 SQL -->
        <property name="show_sql">true</property>

        <!-- 是否对 SQL 进行格式化 -->
        <property name="format_sql">true</property>

        <!-- 指定自动生成数据表的策略 -->
        <property name="hbm2ddl.auto">update</property>

        <!-- 设置 Hibernate 的事务隔离级别 -->
        <property name="connection.isolation">2</property>

        <!-- 删除对象后, 使其 OID 置为 null -->
        <property name="use_identifier_rollback">true</property>

        <!-- 配置 C3P0 数据源 -->
        <property name="hibernate.c3p0.max_size">10</property>
        <property name="hibernate.c3p0.min_size">5</property>
        <property name="c3p0.acquire_increment">2</property>

        <property name="c3p0.idle_test_period">2000</property>
        <property name="c3p0.timeout">2000</property>

        <property name="c3p0.max_statements">10</property>

        <!-- 指定关联的 .hbm.xml 文件 -->
        <mapping resource="hibernates/entities/n21/Customer.hbm.xml"/>
        <mapping resource="hibernates/entities/n21/Order.hbm.xml"/>

    </session-factory>
</hibernate-configuration>

对Order和Customer的增删改查的测试

package hibernates.entities.n21;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.boot.MetadataSources;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.service.ServiceRegistry;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

public class HibernateTest {

    Session session;
    SessionFactory sessionFactory;
    Transaction transaction;

    @Before
    public void init() {
        ServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder().configure().build();
        sessionFactory = new MetadataSources(serviceRegistry).buildMetadata().buildSessionFactory();
        session = sessionFactory.openSession();
        transaction = session.beginTransaction();
    }

    @After
    public void destroy() {
        transaction.commit();
        session.close();
        sessionFactory.close();
    }

    @Test
    public void testMany2OneSave() {
        Customer customer = new Customer();
        customer.setCustomerName("小明");
        Order order1 = new Order();
        order1.setOrderName("AA");
        Order order2 = new Order();
        order2.setOrderName("BB");

        //设定关联关系
        order1.setCustomer(customer);
        order2.setCustomer(customer);

        //执行  save 操作: 先插入 Customer, 再插入 Order, 3 条 INSERT
        //先插入 1 的一端, 再插入 n 的一端, 只有 INSERT 语句.
//        session.save(customer);
//        session.save(order1);
//        session.save(order2);

        //先插入 Order, 再插入 Customer. 3 条 INSERT, 2 条 UPDATE
        //先插入 n 的一端, 再插入 1 的一端, 会多出 UPDATE 语句!
        //因为在插入多的一端时, 无法确定 1 的一端的外键值. 所以只能等 1 的一端插入后, 再额外发送 UPDATE 语句.
        //推荐先插入 1 的一端, 后插入 n 的一端
        session.save(order1);
        session.save(order2);
        session.save(customer);

    }

    @Test
    public void testMany2OneGet() {
        //1. 若查询多的一端的一个对象, 则默认情况下, 只查询了多的一端的对象. 而没有查询关联的
        //1 的那一端的对象!
        Order order = session.get(Order.class, 1);
        System.out.println(order);
        System.out.println(order.getCustomer().getClass().getName());

        session.close();

        //2. 在需要使用到关联的对象时, 才发送对应的 SQL 语句.
        Customer customer = order.getCustomer();
        System.out.println(customer);

        //3. 在查询 Customer 对象时, 由多的一端导航到 1 的一端时,
        //若此时 session 已被关闭, 则默认情况下
        //会发生 LazyInitializationException 异常

        //4. 获取 Order 对象时, 默认情况下, 其关联的 Customer 对象是一个代理对象!

    }

    @Test
    public void testUpdate() {
        Order order = session.get(Order.class, 1);
        order.getCustomer().setCustomerName("555");
    }

    @Test
    public void testDelete() {
        //在不设定级联关系的情况下, 且 1 这一端的对象有 n 的对象在引用, 不能直接删除 1 这一端的对象
        Customer customer = session.get(Customer.class, 1);
        session.delete(customer);
    }
}

二、双向一对多映射关系

实体类的创建(与一中的一样)

编写基础映射文件

Order.hbm.xml的编写:主要是编写<many-to-one>标签

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!-- Generated 2017-12-1 19:54:01 by Hibernate Tools 3.5.0.Final -->
<hibernate-mapping>
    <class name="hibernates.entities.n21.both.Order" table="BOTHORDERS">
        <id name="orderId" type="java.lang.Integer">
            <column name="ORDERID" />
            <generator class="native" />
        </id>
        <property name="orderName" type="java.lang.String">
            <column name="ORDERNAME" />
        </property>
        <many-to-one name="customer" class="hibernates.entities.n21.both.Customer" fetch="join"
                cascade="delete">
            <column name="CUSTOMERID" />
        </many-to-one>
    </class>
</hibernate-mapping>

Customer.hbm.xml的编写

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!-- Generated 2017-12-1 19:54:01 by Hibernate Tools 3.5.0.Final -->
<hibernate-mapping>
    <class name="hibernates.entities.n21.both.Customer" table="BOTHCUSTOMERS">
        <id name="customerId" type="java.lang.Integer">
            <column name="CUSTOMERID" />
            <generator class="native" />
        </id>
        <property name="customerName" type="java.lang.String">
            <column name="CUSTOMERNAME" />
        </property>
        <set name="orders" table="BOTHORDERS" inverse="true" cascade="delete" order-by="CUSTOMERID DESC">
            <key>
                <column name="CUSTOMERID" />
            </key>
            <one-to-many class="hibernates.entities.n21.both.Order" />
        </set>
    </class>
</hibernate-mapping>

核心配置文件hibernate.cfg.xml

<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE hibernate-configuration PUBLIC
        "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
    <session-factory>

        <!-- 配置连接数据库的基本信息 -->
        <property name="connection.username">root</property>
        <property name="connection.password">123456</property>
        <property name="connection.driver_class">com.mysql.jdbc.Driver</property>
        <property name="connection.url">jdbc:mysql:///hibernate</property>

        <!-- 配置 hibernate 的基本信息 -->
        <!-- hibernate 所使用的数据库方言
        <property name="dialect">org.hibernate.dialect.MySQLMyISAMDialect</property>
        <property name="dialect">org.hibernate.dialect.MySQLDialect</property>    -->
        <property name="dialect">org.hibernate.dialect.MySQL5InnoDBDialect</property>    

        <!-- 执行操作时是否在控制台打印 SQL -->
        <property name="show_sql">true</property>

        <!-- 是否对 SQL 进行格式化 -->
        <property name="format_sql">true</property>

        <!-- 指定自动生成数据表的策略 -->
        <property name="hbm2ddl.auto">update</property>

        <!-- 设置 Hibernate 的事务隔离级别 -->
        <property name="connection.isolation">2</property>

        <!-- 删除对象后, 使其 OID 置为 null -->
        <property name="use_identifier_rollback">true</property>

        <!-- 配置 C3P0 数据源 -->
        <property name="hibernate.c3p0.max_size">10</property>
        <property name="hibernate.c3p0.min_size">5</property>
        <property name="c3p0.acquire_increment">2</property>

        <property name="c3p0.idle_test_period">2000</property>
        <property name="c3p0.timeout">2000</property>

        <property name="c3p0.max_statements">10</property>

        <!-- 指定关联的 .hbm.xml 文件 -->
        <!--
        <mapping resource="hibernates/entities/n21/Customer.hbm.xml"/>
        <mapping resource="hibernates/entities/n21/Order.hbm.xml"/>-->
        <mapping resource="hibernates/entities/n21/both/Order.hbm.xml"/>
        <mapping resource="hibernates/entities/n21/both/Customer.hbm.xml"/> 

    </session-factory>
</hibernate-configuration>

Set标签中的三个属性:inverse、 cascade、 order-by

inverse属性:在hibernate中通过对 inverse 属性的来决定是由双向关联的哪一方来维护表和表之间的关系. inverse = false 的为主动方,inverse = true 的为被动方, 由主动方负责维护关联关系
在没有设置 inverse=true 的情况下,父子两边都维护父子关系,在一对多的关系中一般是把一的一端设置为true,这样可以让hibernate减少很多的update语句。

cascade属性:在对象 – 关系映射文件中, 用于映射持久化类之间关联关系的元素, <set>, <many-to-one> 和 <one-to-one> 都有一个 cascade 属性, 它用于指定如何操纵与当前对象关联的其他对象.
       all: 所有情况下均进行关联操作,即save-update和delete。
       none: 所有情况下均不进行关联操作。这是默认值。
       save-update: 在执行save/update/saveOrUpdate时进行关联操作。
       delete: 在执行delete 时进行关联操作。
       all-delete-orphan: 当一个节点在对象图中成为孤儿节点时,删除该节点

order-by属性:<set> 元素有一个 order-by 属性, 如果设置了该属性, 当 Hibernate 通过 select 语句到数据库中检索集合对象时, 利用 order by 子句进行排序,order-by 属性中还可以加入 SQL 函数。
下面是对于这几个属性打的一些相关代码,以及一些发现:

package hibernates.entities.n21.both;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.boot.MetadataSources;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.service.ServiceRegistry;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

public class HibernateTest {

    Session session;
    SessionFactory sessionFactory;
    Transaction transaction;

    @Before
    public void init() {
        ServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder().configure().build();
        sessionFactory = new MetadataSources(serviceRegistry).buildMetadata().buildSessionFactory();
        session = sessionFactory.openSession();
        transaction = session.beginTransaction();
        Customer customer1 = new Customer();
        customer1.setCustomerName("AA");
        Customer customer2 = new Customer();
        customer2.setCustomerName("BB");
        Order order1 = new Order();
        Order order2 = new Order();
        customer1.getOrders().add(order1);
        customer1.getOrders().add(order2);
        customer2.getOrders().add(order1);
        customer2.getOrders().add(order2);
        order1.setCustomer(customer1);
        order2.setCustomer(customer1);
        order1.setCustomer(customer2);
        order2.setCustomer(customer2);
        session.save(customer1);
        session.save(customer2);
        session.save(order1);
        session.save(order2);
    }

    @After
    public void destroy() {
        transaction.commit();
        session.close();
        sessionFactory.close();
    }

    @Test
    public void testInverse() {
        //1.可以在 1 的一端的 set 节点指定 inverse=true, 来使 1 的一端放弃维护关联关系!
        //2.通过多的一端改变来改变表中的数据:
        Order order3 = session.get(Order.class, 1);
        order3.setOrderName("HH");
        order3.getCustomer().setCustomerName("BB");
        //3.通过一的一端来修改表中的数据:
        Customer customer3 = session.get(Customer.class, 1);
        customer3.setCustomerName("DD");
        customer3.getOrders().iterator().next().setCustomer(customer3);
        System.out.println(customer3.getOrders());

    }

    @Test
    public void testCascade() {
        //当<set> 中的 cascade的属性值为delete时一的一端的数据被删除时,它所关联的多的一端也被删除,<many-to-one>中的
        //cascade也具有同样的功能
        Customer customer3 = session.get(Customer.class, 1);
        session.delete(customer3);
        Order order3 = session.get(Order.class, 1);
        session.delete(order3);
    }

    @Test
    public void testOrderBy() {
        //下面两句输出语句都会使Hibernate查询customer关联的order表,然后按照order-by的设定排序查询
        Customer customer3 = session.get(Customer.class, 1);
        System.out.println(customer3.getOrders());
        System.out.println(customer3.getCustomerName());
    }

}
时间: 2024-08-28 06:11:27

学习笔记之Hibernate_映射关系之一对多映射关系的相关文章

学习笔记:类与类之间的关系

转自:http://www.cnblogs.com/liuling/archive/2013/05/03/classrelation.html(谢谢楼主分享) 一.继承关系      继承指的是一个类(称为子类.子接口)继承另外的一个类(称为父类.父接口)的功能,并可以增加它自己的新功能的能力.在Java中继承关系通过关键字 extends明确标识,在设计时一般没有争议性.在UML类图设计中,继承用一条带空心三角箭头的实线表示,从子类指向父类,或者子接口指向父接口. 二.实现关系      实现

EF Code First 学习笔记:表映射

多个实体映射到一张表 Code First允许将多个实体映射到同一张表上,实体必须遵循如下规则: 实体必须是一对一关系 实体必须共享一个公共键 观察下面两个实体: public class Person { [Key] public int PersonId { get; set; } public int SocialSecurityNumber { get; set; } public string FirstName { get; set; } public string LastName

[javase学习笔记]-6.2 类与对象的关系

这一节我们来看一下类与对象之间的关系. 我们学习java语言,目的就是用java语言对现实生活中的事物进行描写叙述.那么我们如何来描写叙述呢.这就引出了类,我们在实际实现时,是通过类的形式来体现的. 那么对于现实生活中的事物怎样描写叙述呢? 我们在现实生活中对于事物描写叙述通常仅仅关注两个方面,一个是属性,还有一个就是行为. 那么非常自然.计算机的描写叙述就产生出详细的对象. 比方我们要描写叙述一个小汽车.那么我们要怎么描写叙述呢?通过上面关注两个方面,我们非常轻松的从两个方面进行下面描写叙述:

WebApi学习笔记09:OData中的实体关系

1.概述 本例是在学习系列07介绍的项目基础上进行演练…… 2.添加实体 在Models文件夹下,添加Supplier.cs类,代码: using System.Collections.Generic; namespace ProductService.Models { public class Supplier { public int Id { get; set; } public string Name { get; set; } public ICollection<Product>

Django学习笔记3一对多,多对多关系解析

Django 的 ORM 有多种关系:一对一,多对一,多对多. 各自定义的方式为 : 一对一: OneToOneField 多对一: ForeignKey 多对多: ManyToManyField 上边的描述太过数据而缺乏人性化,我们来更人性化一些: 多个属于一个,即 belong to :  ForeignKey,多个属于一个 一个有一个,即 has one: OneToOneField 一个有很多个,即 has many:  lots of A belong to B 与 B has man

Unity学习笔记(2):注册映射

在上一篇文章中(认识Unity)中概要介绍了Unity和Ioc,本节主要介绍IoC中的注册映射,并使用代码和配置文件两种方式进行说明. 定义依赖注入相关信息 定义ILogger接口 public interface ILogger { void Info(string message); void Warning(string message); void Error(string message); void Fatal(string message); void Exception(stri

转:C#制作ORM映射学习笔记三 ORM映射实现

现在开始实现ORM的主体模块,首先需要在项目中新建一个类,命名为DbAccess,然后在项目的引用中添加两个dll,分别是MySql.Data.dll和System.Data.SQLite.dll,这两个dll都可以在对应的数据库官网上下载到,为了方便我这里也提供一个下载地址.添加好dll后需要在DbAccess中添加几个名空间,具体代码如下: using System; using System.Collections; using System.Collections.Generic; us

Spring 学习笔记(五)—— Bean之间的关系、作用域、自动装配

继承 Spring提供了配置信息的继承机制,可以通过为<bean>元素指定parent值重用已有的<bean>元素的配置信息. <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XML

linux C学习笔记04--内存映射

内存映射代码,打开一个文件与映射到内存中,对内存和文件的修改都会反映到文件中来,反之亦然,先贴代码,以后再完善: /************************************************************************* > File Name: memory_map.c > Author: hailin.ma > Mail: [email protected] > Created Time: Thu 28 May 2015 08:20:5