文档章节

学习hibernate(五) -- hibernate映射关系

XuePeng77
 XuePeng77
发布于 2016/04/07 00:00
字数 1933
阅读 74
收藏 4

组合关系

    在开发时,有一种情况,有一张数据表的数据来自于多个对象。比如,一个computer(电脑)表,其中有电脑的基本信息、CPU信息、显卡信息、主板信息和内存信息等等,对应的实体对象则是电脑对象、CPU对象、显卡对象和内存对象。这种情况下可以使用组合关系映射。

    以电脑与CPU为例,Computer类中包含了一个Cpu类,在*.hbm.xml文件中,使用component来进行组合关系映射。

    看一下这两个实体类的代码和映射文件:

package cn.net.bysoft.model;

public class Computer {
//getter and setter

    private int id;
    private String name;
    private Cpu cpu;
}
package cn.net.bysoft.model;

public class Cpu {

    //getter and setter

    private String name;
}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="cn.net.bysoft.model">
    <class name="Computer" table="computer">
        <id name="id" type="integer" column="ID">
            <!-- 指定主键的生成方式,native是使用数据库本地的方式 -->
            <generator class="native"></generator>
        </id>
        <property name="name" type="string" column="NAME"></property>
        <!-- 使用组合关系映射,CPU的Name信息存放在Cpu_Name字段中。 -->
        <component name="cpu" class="Cpu">
            <property name="name" type="string" column="CPU_NAME"></property>
        </component>
    </class>
</hibernate-mapping>

    生成的数据表并测试save方法:

@Test
    public void testComponent() throws IOException {
        //    save一个组合关系对象。
        Computer computer = new Computer();
        computer.setName("pc");
        Cpu cpu = new Cpu();
        cpu.setName("Inter");
        computer.setCpu(cpu);
        session.save(computer);
    }

一对多与多对一

    一对多与多对一关联,一般用于一个对象包含另一个对象的集合,被包含的对象中存在包含对象的实体,比如一个customer可以有多比订单(order)。在数据表中,order表有customer表的外键。

    在*.hbm中,一的一端使用set标签设置多的一端的集合,在set中加入key与one-to-many。

    多的一端使用<one-to-may>属性配置一对多。

    看一下实体类代码和配置文件:

package cn.net.bysoft.model1;

import java.util.HashSet;
import java.util.Set;

public class Customer {
    getter/setter属性
    
    private int Id;
    private String name;
    //    一对用户可以有多个订单。
    private Set<Order> orders = new HashSet<Order>();
}
package cn.net.bysoft.model1;

public class Order {
    getter/setter属性
    
    private int id;
    private String name;
    //    每个订单都属于一个用户。
    private Customer customer;
}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
    <class name="cn.net.bysoft.model1.Customer" table="CUSTOMERS">
        <id name="id" type="integer" column="ID">
            <!-- 指定主键的生成方式,native是使用数据库本地的方式 -->
            <generator class="native"></generator>
        </id>
        <property name="name" type="string" column="NAME"></property>
        <!-- 一对多 -->
        <set name="orders" table="ORDERS">
            <key column="CUSTOMER_ID"></key>
            <one-to-many class="cn.net.bysoft.model1.Order"/>
        </set>
    </class>
</hibernate-mapping>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
    <class name="cn.net.bysoft.model1.Order" table="ORDERS">
        <id name="id" type="integer" column="ID">
            <!-- 指定主键的生成方式,native是使用数据库本地的方式 -->
            <generator class="native"></generator>
        </id>
        <property name="name" type="string" column="NAME"></property>
        <!-- 多对一 -->
        <many-to-one name="customer" class="cn.net.bysoft.model1.Customer" column="CUSTOMER_ID">
        </many-to-one>
    </class>
</hibernate-mapping>

    新增和删除的时候有一些需要注意的地方,看一段save代码:

    @Test
    public void testOneToManySave() {
        Customer customer = new Customer();
        customer.setName("Kobe");

        Order order1 = new Order();
        order1.setName("buy book");
        Order order2 = new Order();
        order2.setName("buy ball");

        customer.getOrders().add(order1);
        customer.getOrders().add(order2);

        order1.setCustomer(customer);
        order2.setCustomer(customer);

        session.save(customer);
        session.save(order1);
        session.save(order2);

        /**
         * output: Hibernate: 
         * insert into CUSTOMERS (NAME) values (?) 
         * insert into ORDERS (NAME, CUSTOMER_ID) values (?, ?) 
         * insert into ORDERS (NAME, CUSTOMER_ID) values (?, ?)
         * */
    }

    先save一的一端,在save多的一端,会打印三条sql语句,是正常的。如果先保存多的一端在保存一的一端,会输出七条sql语句,其中有4条是update语句,因为先保存多的一端,此时并没有一的一端的主键,等到保存好一的一端后,在回头由两端都进行update。

        session.save(order1);
        session.save(order2);
        session.save(customer);

        /**
         * output: 
         * Hibernate: insert into ORDERS (NAME, CUSTOMER_ID) values (?,?) 
         * Hibernate: insert into ORDERS (NAME, CUSTOMER_ID) values (?, ?)
         * Hibernate: insert into CUSTOMERS (NAME) values (?) 
         * Hibernate: update ORDERS set NAME=?, CUSTOMER_ID=? where ID=? 
         * Hibernate: update ORDERS set NAME=?, CUSTOMER_ID=? where ID=? 
         * Hibernate: update ORDERS set CUSTOMER_ID=? where ID=? 
         * Hibernate: update ORDERS set CUSTOMER_ID=? where ID=?
         * */

    正常来说,不需要两端都进行update维护,要解决该问题需要在一端加入inverse属性,建议由多的一端去控制,所以在Customer.hbm.xml中的set节点中加入:

<set name="orders" table="ORDERS" inverse="true">

    在进行保存时,update语句减少了,只由多的一端维护关系:

    再来说说delete。删除时在不设置级联的情况下,不能删除一的一端,因为这一端的主键被关键关联着:

    @Test
    public void testOneToManyDelete() {
        Customer customer = (Customer) session.get(Customer.class, 1);
        session.delete(customer);
        /**
         * output: 
         * INFO: HHH000010: On release of batch it still contained JDBC statements
         * */
    }

    使用级联关系的属性是cascade,该属性有三个值,分别是:

  • delete:删除一的一端,会连带着删除多的一端;

  • delete-orphan:一的一端使用多的一端的集合的clear属性可以删除多的一端;

  • save-update:值保存一的一端,多的一端会自动保存;

    在设置好级联关系后,可直接删除一的一端:

<set name="orders" table="ORDERS" inverse="true" cascade="delete">

    在项目中建议使用手动控制关联关系。

一对一

    有两种情况均为一对一关联关系,一个部门有一个部门经理。可以使用某一个字段做外键,也可以使用主键做外键。先来看看主外键情况做一对一。

    在Manager对象的配置文件中加入<one-to-one>节点,而Dept对象中加入<many-to-one>节点,对该节点加入unique属性进行唯一约束,下面是实体类与配置文件内容:

package cn.net.bysoft.model1;

public class Dept {
    //getter/setter

    private int id;
    private String name;
    private Manager manager;
}
package cn.net.bysoft.model1;

public class Manager {
    //getter/setter
    
    private int id;
    private String name;
    private Dept dept;
}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
    <class name="cn.net.bysoft.model1.Dept" table="DEPT">
        <id name="id" type="integer" column="ID">
            <!-- 指定主键的生成方式,native是使用数据库本地的方式 -->
            <generator class="native"></generator>
        </id>
        <property name="name" type="string" column="NAME"></property>
        <!-- 多对一 -->
        <many-to-one name="manager" class="cn.net.bysoft.model1.Manager"
            column="MANAGER_ID" unique="true"></many-to-one>
    </class>
</hibernate-mapping>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
    <class name="cn.net.bysoft.model1.Manager" table="MANAGER">
        <id name="id" type="integer" column="ID">
            <!-- 指定主键的生成方式,native是使用数据库本地的方式 -->
            <generator class="native"></generator>
        </id>
        <property name="name" type="string" column="NAME"></property>
        <!-- 一对一 -->
        <one-to-one name="dept" class="cn.net.bysoft.model1.Dept" property-ref="manager"></one-to-one>
    </class>
</hibernate-mapping>

    接下来是主键与主键做一对一关系,实体类无需改变,只需要修改dept的配置文件,将id节点的class修改成foreign模式,将many-to-one修改成one-to-one,添加constrained属性等于true,具体如下:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
    <class name="cn.net.bysoft.model1.Dept" table="DEPT">
        <id name="id" type="integer" column="ID">
            <!-- 指定主键的生成方式,native是使用数据库本地的方式 -->
            <generator class="foreign">
                <param name="property">manager</param>
            </generator>
        </id>
        <property name="name" type="string" column="NAME"></property>
        <one-to-one name="manager" class="cn.net.bysoft.model1.Manager" constrained="true">
        </one-to-one>
    </class>
</hibernate-mapping>

    增删改查方法的调用与一对多多对一一样。

多对多

    用数据表描述多对多,需要有三张表,A表,B表,A-R-B表。

    用对象描述多对多,A对象中有B对象的集合,B对象中也有A对象的集合。

    举个例子,现在有订单类与商品类,一个订单中可以有多个商品,而一个商品也可以属于多个订单。看一下实体类的代码:

package cn.net.bysoft.model1;

import java.util.HashSet;
import java.util.Set;

public class Orders {

    //getter and setter

    private int id;
    private String name;
    private Set<Products> products = new HashSet<Products>();
}
package cn.net.bysoft.model1;

import java.util.HashSet;
import java.util.Set;

public class Products {
    //getter and setter

    private int id;
    private String name;
    private Set<Orders> orders = new HashSet<Orders>();
}

    两个对象的配置文件也很像,每个配置文件中都有set节点,但是在多对多中,必须有一个set的inverse=true,具体如下:

    使用方式与一对多多对一相同。

© 著作权归作者所有

XuePeng77
粉丝 47
博文 145
码字总数 193261
作品 0
丰台
私信 提问
Hibernate映射——一对一单向关联映射(五)

映射原理 两个实体对象之间是一对一的关联映射,即一个对象只能与另外唯一的一个对象相对应。例如:一个人(Person)只有一张身份证(IdCard)。我们看一下这个例子的对象模型,如下图所示: 对象...

architect刘源源
2018/01/11
12
0
Hibernate 学习教程

第1课 课程内容. 6 第2课Hibernate UML图. 6 第3课 风格. 7 第4课 资源. 7 第5课 环境准备. 7 第6课 第一个示例HibernateHelloWorld 7 第7课 建立Annotation版本的HellWorld 9 第8课 什么是O...

梅_95
2016/08/15
51
0
Hibernate入门

Hibernate简介 Hibernate是一个开放源代码的对象关系映射框架,它对JDBC进行了非常轻量级的对象封装,它将POJO与数据库表建立映射关系,是一个全自动的ORM框架,hibernate可以自动生成SQL语句...

iborder
2016/10/31
40
0
Hibernate 学习参考

第1课 课程内容. 6 第2课Hibernate UML图. 6 第3课 风格. 7 第4课 资源. 7 第5课 环境准备. 7 第6课 第一个示例HibernateHelloWorld 7 第7课 建立Annotation版本的HellWorld 9 第8课 什么是O...

长平狐
2012/11/12
5K
0
学习hibernate感受(-)

做为一个初学Hibernate的过来人,想对将要学习Hibrnate的高手手们谈一下自己的感受! 首先我们要弄清楚,我们为什么要学习Hibernate?Hibernate是什么东东? 在这里我们要明确,我们是java程...

WYDPH
2012/10/01
220
1

没有更多内容

加载失败,请刷新页面

加载更多

OSChina 周六乱弹 —— 早上儿子问我他是怎么来的

Osc乱弹歌单(2019)请戳(这里) 【今日歌曲】 @凉小生 :#今日歌曲推荐# 少点戾气,愿你和这个世界温柔以待。中岛美嘉的单曲《僕が死のうと思ったのは (曾经我也想过一了百了)》 《僕が死の...

小小编辑
今天
2.4K
15
Excption与Error包结构,OOM 你遇到过哪些情况,SOF 你遇到过哪些情况

Throwable 是 Java 中所有错误与异常的超类,Throwable 包含两个子类,Error 与 Exception 。用于指示发生了异常情况。 Java 抛出的 Throwable 可以分成三种类型。 被检查异常(checked Exc...

Garphy
今天
41
0
计算机实现原理专题--二进制减法器(二)

在计算机实现原理专题--二进制减法器(一)中说明了基本原理,现准备说明如何来实现。 首先第一步255-b运算相当于对b进行按位取反,因此可将8个非门组成如下图的形式: 由于每次做减法时,我...

FAT_mt
昨天
40
0
好程序员大数据学习路线分享函数+map映射+元祖

好程序员大数据学习路线分享函数+map映射+元祖,大数据各个平台上的语言实现 hadoop 由java实现,2003年至今,三大块:数据处理,数据存储,数据计算 存储: hbase --> 数据成表 处理: hive --> 数...

好程序员官方
昨天
61
0
tabel 中含有复选框的列 数据理解

1、el-ui中实现某一列为复选框 实现多选非常简单: 手动添加一个el-table-column,设type属性为selction即可; 2、@selection-change事件:选项发生勾选状态变化时触发该事件 <el-table @sel...

everthing
昨天
21
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部