hibernate的3种继承映射关系总结——TPH,TPS,TPC

Java类中有继承关系,相应的在hibernate中,也有继承关系,子类反应到数据库中,就有多种实现形式了,子类和父类可以映射到同一张表中,子类也可以单独映射成一张表,但是用不同的标签实现,子类表和父类表的关系也不同。

下面对以前做的project进行总结一下

为了将程序领域中的继承关系反映到数据 中,Hibernate为我们提供了3中方案:

第一种方案:每棵类继承树一张表(Table Per Hierarchy)TPH

第二种方案:每个子类一张表(Table Per Subclass)TPS

第三种方案:每个具体的类一张表(Table Per Concrete class)TPC

就下图的继承关系来阐明三种方法:

对应的三个PO:

Person.java

package com.hust.PO;

public class Person {
     private Integer id;
     private String name;   //姓名
     private Integer age;    //年龄
     private String sex;     //性别

    //省略getter和setter函数
}

Student.java

package com.hust.PO;

public class Student extends Person {
     //private Integer sid;   //TPS每个子类一张表时,要新增这个属性,学生标识,与父类person内连接
       private String sno;    //学号
       private String school;  //学校

       //省略getter和setter函数
}

Worker.java

package com.hust.PO;

public class Worker extends Person {
	 //private Integer wid;      //TPS每个子类一张表时,增加这个属性,工人标识,与父类person内连接
	 private String wno;      //工号
         private Double salary;   //工资
     //省略getter和setter函数
}

一.每棵类继承树一张表(Table Per Hierarchy)TPH

http://blog.csdn.net/tuke_tuke/article/details/49981013

所谓一棵继承树一张表,就是子类属性和父类属性放在一张表中,但是要指定鉴别器列,用subclass一定要有判断类型的一个列,鉴别器指定记录属于哪个类型

person表

只有一个父类person表,只有一个映射文件Person.hbm.xml

Person.hbm.xml

<?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="com.hust.PO">
    <!-- 一个继承树一张表 -->
    <!-- 父类 -->
    <class name="Person" table="person">
        <id column="id" name="Id" type="integer">
            <!-- 主键生成策略为 '分配'  -->
            <generator class="assigned"></generator>
        </id>
        <!-- 鉴定列,区分列 discriminator 鉴别器-->
        <discriminator column="Type" type="string"></discriminator>

        <property column="Name" name="name" type="string"></property>
        <property column="Age" name="age" type="integer"></property>
        <property column="Sex" name="sex" type="string"></property>  

    <!-- 子类,其鉴定列值为'stu' name是PO类名-->
    <subclass name="Student" discriminator-value="stu">
        <property column="School" name="school" type="string"></property>
        <property column="Sno" name="sno" type="string"></property>
    </subclass>  

    <!-- 子类,其鉴定列值为'worker' name是PO类名-->
    <subclass name="Worker" discriminator-value="worker">
        <property column="Wno" name="wno" type="string"></property>
        <property column="Salary" name="salary" type="double"></property>
    </subclass>  

    </class>
</hibernate-mapping>

所谓的将整个继承树映射到同一个表当中,即子类的信息,全部映射到了父类对应的表中。<discriminator>标签用于在表中创建一个标识列,其"column"属性指定标识列的列名,"type"指定了标识列的类型。注意,一定要指定鉴别器,它的作用是在父类的映射表中,添加了一个type的列,用来鉴别员工是属于哪个子类,并且在每个类的标签中要指定鉴别器值。

结果:

二,每个子类一张表(Table Per Subclass)TPS

http://blog.csdn.net/tuke_tuke/article/details/50082457

所谓“每个子类一张表”:父类一张表,每个子类一张表,父类的表保存公共有信息,子类的表只保存自己特有的信息

三个表的关系:

person表

student表

worker表

只有一个父类映射文件Person.hbm.xml,三张表

Person.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">
<hibernate-mapping package="com.hust.PO">
    <!-- Person表 -->
    <class name="Person" table="person">
       <!-- person 表保存公共属性 -->
        <id name="id">
            <!-- 父类的主键生成策略为‘分配’ -->
            <generator class="assigned"></generator>
        </id>
        <property name="name" column="Name" type="string"></property>
        <property name="sex" column="Sex" type="string"></property>
        <property name="age" column="Age" type="java.lang.Integer"></property>  

        <!-- student表 ,name是类名。table是对应的表名-->
        <joined-subclass name="Student" table="student">
            <key column="Sid"></key>  <!-- 指定了子类和父类之间是通过哪个字段来关联的 ,这里的关联是内连接-->
            <property column="Sno" name="sno" type="string" ></property> <!-- 子类特征属性 -->
            <property column="School" name="school" type="string" ></property>    <!-- 子类特征属性 -->
        </joined-subclass>  

        <!-- worker表 -->
        <joined-subclass name="Worker" table="worker">
            <key column="Wid"></key>
            <property column="Wno" name="wno" type="string" ></property>  <!-- 子类特征属性 -->
            <property column="Salary" name="salary" type="double" ></property>  <!-- 子类特征属性 -->
        </joined-subclass>
    </class>
</hibernate-mapping>  

<joined-subclass>标签需要包含一个key标签,这个标签指定了子类和父类之间是通过哪个字段来关联的。

根据People.hbm.xml生成表结构, 可以看到,父类对应的表保存公有信息,子类对应的表保存独有信息,子类和父类对应的表使用一对一主键关联的方式关联起来

用joined-subclass只能创建为子类单独创建表,子类对应的表的主键和外键都是其父类的主键。注意,joined-subclass不能和subclass混合使用

结果:

person表结果                         student表结果                             worker表结果

           

三,每个具体的类一张表(Table Per Concrete class)TPC

http://blog.csdn.net/tuke_tuke/article/details/50085449

所谓是“每个具体类一张表(table per concrete class)”的意思是:使继承体系中每一个子类都对应数据库中的一张表。每一个子类对应的数据库表都包含了父类的信息,并且包含了自己独有的属性。每个子类对应一张表,而且这个表的信息是完备的,即包含了所有从父类继承下来的属性映射的字段

只有两个表的关系:

student表

worker表

注意:只要一个父类映射表Person.hbm.xml,两张表

Person.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">
<hibernate-mapping package="com.hust.PO">
    <!-- table per concrete(TPC) (a. 具体的,实际的) -->
    <!-- 每一个具体类一张表 -->
    <!-- 虚拟选项为'true' -->
    <class name="Person" table="person" abstract="true">  <!-- 多设置一个属性abstract="true",因为根本就没有person表 -->
    <id column="Id" name="id" type="integer">
        <!-- 主键的生成策略为'分配' -->
        <generator class="assigned"></generator>
    </id>
    <property column="Name" name="name" type="string"></property>
    <property column="Sex" name="sex" type="string"></property>
    <property column="Age" name="age" type="integer"></property>  <!-- 公共属性 -->

    <!--student具体类-->
    <union-subclass name="Student" table="student">
        <property column="Sno" name="sno" type="string"></property>      <!-- 特征属性 -->
        <property column="School" name="school" type="string"></property>  <!-- 特征属性 -->
    </union-subclass>  

    <!--worker具体类-->
    <union-subclass name="Worker" table="worker">
        <property column="Wno" name="wno" type="string"></property>  <!-- 特征属性 -->
        <property column="Salary" name="salary" type="double"></property>  <!-- 特征属性 -->
    </union-subclass>  

    </class>
</hibernate-mapping>  

<class>标签中的"abstract"属性如果值为true则,不会生成表结构。如果值为false则会生成表结构(貌似是根据映射文件生成表结构,不是很理解),但是不会插入数据。

把父类设为抽象的类,并且在映射文件中,把父类设置为abstract="true",那么就不会再数据库中生成父类对应的表了,父类就只起到一个抽象的作用了。

union-subclass是将父类中的属性,添加到子类对应的表中去了.

结果:

student表

worker表

三种方式的优缺点:

1,首先表中引入的区分子类的字段,也就是包括了描述其他字段的字段。其次,如果某个子类的某个属性不能为空,那么在数据库一级不能设置该字段not null(非空),维护起来方便,只需要修改一个表,灵活性差,表中冗余字段会随着子类的增多而越来越多。在任何情况下,都只需处理一个表,对于单个对象的持久话操作只需要处理一个表

2,这种设计方式完全符合关系模型的设计原则,且不存在冗余,维护起来比较方便,对每个类的修改只需要修改其所对应的表,灵活性很好,完全是参照对象继承的方式进行配置,对于父类的查询需要使用左外链接,对于子类查询需要使用内链接,对于子类的持久话至少要处理两个表

3,这种设计方式符合关系模型的设计原则,但有表中存在重复字段的问题。如果需要对基类进行修改,则需要对基类以及该类的子类所对应的所有表都进行修改,映射的灵活性很大,子类可以包括基类属性在内的每一个属性进行单独配置,对于子类的查询只需要访问单独的表,对父类查询怎需要检索所有的表,对于单个对象持久话操作只需要处理一个表

时间: 2024-10-14 12:00:36

hibernate的3种继承映射关系总结——TPH,TPS,TPC的相关文章

Hibernate学习2之继承映射与C3P0连接池

一.继承映射的需要 关系数据库的表之间不存在继承关系, 但为了将面向对象中的继承关系映射到关系数据库中, 可以使用以下三种继承映射策略: -每个继承层次一张表 -每个具体类一张表 -每个类一张表. 二.对比 --每个继承层次一张表: (优点)最简单.执行效率最高(因为无需进行任何关联操作) (缺点)存在冗余字段:在数据表中需要加入额外的区分各个类的字段: 同时不允许为子类成员属性对应的字段定义为not null约束. --每个具体类一张表: (优点)数据结构清晰,且可以对子类成员属性映射的字段定

EF里的继承映射关系TPH、TPT和TPC的讲解以及一些具体的例子

EF里的继承映射关系TPH.TPT和TPC的讲解以及一些具体的例子 本章节讲解EF里的继承映射关系,分为TPH.TPT.TPC.具体: 1.TPH:Table Per Hierarchy 这是EF的默认的继承映射关系:一张表存放基类和子类的所有列,自动生成的discriminator列用来区分基类和子类的数据.新建一个度假村Resort实体类试试: /// <summary> /// 度假村类 /// </summary> public class Resort : Lodging

hibernate笔记--继承映射关系的三种实现方式

单表继承映射(一张表): 假设我们现在有三个类,关系如下: Person类有两个子类Student和Teacher,并且子类都具有自己独有的属性.这种实体关系在hibernate中可以使用单表的继承映射来建表,最后生成的表是这样的: 可以看到我们只需要建立一张表就可以维护这个关系,这种方式就是单表继承映射,下面介绍配置方法: 新建实体类Person ,Student,和Teacher : public class Person { private int id; private String n

一口一口吃掉Hibernate(七)——继承映射

前几篇博文中讲到了常用的几种关联映射.其实hibernate中还有一种"省劲儿"的映射,那就是--"继承映射". 学了这么多的关系映射了,继承映射,从字面上也能了解到猜到几分.没错,继承映射就是为继承树而设置的一种映射方案. 继承映射的实现有三种策略: 单表继承.每棵类继承树使用一个表 类表继承.每个子类生成一个表. 具体表继承.每个类生成一个表. 我们还是用实例来说明一下,直接上图吧: Pig和Bird都继承自Animal,它们都有id,name,sex,但是Pi

千山万水之Hibernate(八)——继承映射

类之间的关系,我们可以分为四种:关联.依赖.继承.实现.而我们所说的实体类之间的关系往往会想到两种:关联和继承,其他两种为什么会不是很常用?首先类之间的依赖是一种比较弱的关系,在代码上可以理解为在一个类的方法的参数上或方法内部对另一个类有引用或调用,引用类或调用类不属于原始类的变量类型,实体类之间一般不存在方法,也就谈不上依赖了.实现描述的是类与接口的关系,一般接口用于定义方法,也就是相当于定义出一些规范,不进行实现. 在前面几篇文章中,我们了解和学习了如何使用Hibernate进行实体类之间的

hibernate注解方式来处理映射关系

在hibernate中,通常配置对象关系映射关系有两种,一种是基于xml的方式,另一种是基于annotation的注解方式,熟话说,萝卜青菜,可有所爱,每个人都有自己喜欢的配置方式,我在试了这两种方式以后,发现使用annotation的方式可以更简介,所以这里就简单记录下通过annotation来配置各种映射关系,在hibernate4以后已经将annotation的jar包集成进来了,如果使用hibernate3的版本就需要引入annotation的jar包. 一.单对象操作 @Entity

Hibernate(三) 之 映射关系

一.概念: 关系:名词,事物之间相互作用.相互联系的状态. 关联:名词:表示对象(数据库表)之间的关系:动词:将对象(数据库表)之间通过某种方式联系起来. 映射:将一种形式转化为另一种形式,包括关系. 级联:动词,有关系的双方中操作一方,另一方也将采取一些动作. 值类型:对象不具备数据库同一性,属于一个实体实例其持久化状态被嵌入到所拥有的实体的表行中,没有标识符. 实体类型:具有数据库标识符. 二.数据库: 1.关系 2.1.1.一对一.一对多.多对多 2.1.2.如何表示? 外键+索引 2.级

hibernate(四) 双向多对多映射关系

序言 莫名长了几颗痘,真TM疼,可能是现在运动太少了,天天对着电脑,决定了,今天下午花两小时去跑步了, 现在继上一章节的一对多的映射关系讲解后,今天来讲讲多对多的映射关系把,明白了一对多,多对多个人感觉还是比较容易的,需要理清楚其数据库关系图,那么你就拿下了它.映射文件的配置还是那么些死东西. --WH 一.小疑问的解答 问题一:到这里,有很多学习者会感到困惑,因为他不知道使用hibernate是不是需要自己去创建表,还是hibernate全自动,如果需要自己创建表,那么主外键这种设置也是自己设

Hibernate之实现一对一关联映射关系

Hibernate中实现一对一映射有基于外键的方式和基于主键的方式.由于基于主键方式的映射在实现删除等操作时存在的问题且不够灵活,一般建议使用基于外键的方式实现. 以个人与身份证的关系为例(主要看映射文件的配置和实体类): 基于外键的方式: package test.hibernate.hbmOneToOne; public class Person { private Integer id; private String name; private IDCard idCard; public