初识Hibernate之继承映射

     前面的两篇文章中,我们介绍了两张表之间的各种相互关联映射关系,但往往我们也会遇到两张表甚至多张表之间共有着多个相同的字段。例如:

如图,student表和teacher表共同具有id,name,age等字段,而我们的继承映射就是这样的一个思想,抽象出这些共有的字段为一张父表,让子表对其进行继承,这样就可以大大降低我们实体类代码的冗余性,增强其结构的完善。

Hibernate支持以下三种数据表的生成策略:

  • 每个类分层结构一张表
  • 每个子类一张表
  • 每个具体类一张表

一、每个类分层结构一张表      对于这种数据表的生成策略,最终Hibernate会在数据库中生成一张数据表,这张数据表的结构会是如下的:

无论你是student记录还是teacher记录,都会被存储到这张集成的新表中。下面是实现代码:

public class Person {
    private int id;
    private String name;
    //省略get,set方法
}
public class Student extends Person {
    private int grade;
    //省略get,set方法
}
public class Teacher extends Person {
    private int salary;
    //省略get,set方法
}

下面是映射配置文件的书写:

<class name="Person" abstract="true" table="newTable">
    <id name="id">
        <generator class="assigned"/>
    </id>
    <!--指定鉴别器列的名称和类型-->
    <discriminator column="type" type="java.lang.String"/>
    <property name="name"/>
    <!--指定集成到新表的子实体类-->
    <subclass name="Student" discriminator-value="stu">
        <!--配置继承类中其他属性-->
        <property name="grade"/>
    </subclass>
    <subclass name="Teacher" discriminator-value="tea">
        <property name="salary"/>
    </subclass>
</class>

abstract="true"指定Hibernate不用将Person表生成具体表,只需要生成一张集成的新表即可。table="newTable"则指定了新表的表名,鉴别器就是用来区分当前记录时student或是teacher的一个标记,它会在新表中生成一个字段,而该字段的名称和类型都在此处进行指定。

subclass标签用于配置需要集成到新表中子实体类的一些属性等内容。下面我们通过插入操作了解这种映射策略对具体数据库的实际操作。

Student student = new Student();
student.setId(1);
student.setName("stu1");
student.setGrade(100);

Teacher teacher  = new Teacher();
teacher.setId(2);
teacher.setName("tea1");
teacher.setSalary(10000);

session.save(student);
session.save(teacher);

将两条不同类型的记录保存到数据库中,

newTable是一张综合的表,主要由student表和teacher表集成而来,对应于student表的记录salary字段的值为空,对应于teacher表记录的grade字段值为空。那在我们取数据的时候,Hibernate该如何区分当前记录对应的是哪个实体类的呢?

Person person = (Person)session.get(Person.class,1);
if(person instanceof Student){
    Student student1 = (Student)person;
    System.out.println("i am student,my grade is:"+student1.getGrade());
}

实际上,Hibernate使用多态来对数据记录进行接收,无论你是Student记录或teacher记录,都可以被person类型接收。使用这种策略方式映射数据表只会生成一张表,但是很大的一个问题是,当很多张表进行集成的时候会导致表结构复杂混乱。

二、每个具体类映射成一张表      这种数据表的生成策略会为每个实体类生成一张数据表,就上述例子而言,会为person,student,teacher都生成一张表。首先我们看映射配置文件:

<class name="Person">
    <id name="id">
        <generator class="assigned"/>
    </id>
    <property name="name"/>
    <union-subclass name="Student" table="students">
        <property name="grade"/>
    </union-subclass>
    <union-subclass name="Teacher" table="teachers">
        <property name="salary"/>
    </union-subclass>
</class>

这里的配置其实不需要多的解释,union-subclass告诉Hibernate当前配置的实体类是person类的子类,并用table属性指定对应数据库的表名。下面我们通过插入数据来看看具体生成的表的结构:

很明显,我们的person表只起到一个模板的效果并没有什么实际的价值,而我们students表和teachers表的id,name字段都是从person表中继承得到的。

三、每个子类一张表      这种数据表的生成策略的主要思想就是将公共的信息存放在父表中,子表只保存自己独有的字段信息了。例如:

<class name="Person">
    <id name="id" column="id">
       <generator class="native"/>
    </id>
    <property name="name"/>
    <joined-subclass name="Student" table="students">
        <key column="sId" />
        <property name="grade"/>
    </joined-subclass>
    <joined-subclass name="Teacher" table="teachers">
        <key column="tId"/>
        <property name="salary"/>
    </joined-subclass>
</class>

我们使用 joined-subclass来配置继承子类,在Hibernate生成数据表的时候会将student和teacher表的主键作为外键关联父表的主键。下面是插入数据:

Student student = new Student();
student.setName("stu1");
student.setGrade(12);

Teacher teacher = new Teacher();
teacher.setName("tea1");
teacher.setSalary(1233);

session.save(student);
session.save(teacher);

显然,我们student或者teacher表不再需要存放name或者其他共有字段的信息,只需要通过自己的主键去查找父表即可得到。

至此,有关继承映射的三个策略已经介绍结束,总结不到之处,望指出。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏我的博客

Tp3.1.2模型学习

1.模型定义 命名规则是除去表前缀的数据表名称,采用驼峰命名,并且首字母大写,然后加上后缀Model 其中tableName是不包含表前缀的数据表名称,一般用...

3184
来自专栏安恒网络空间安全讲武堂

Sqli_labs65关通关详解(下)

less-31 逻辑跟30关一样,只不过 $id = '"' .$id. '"'; $sql="SELECT * FROM users WHERE id=($i...

2638
来自专栏加米谷大数据

Hive的数据类型

本文介绍hive的数据类型,数据模型以及文件存储格式。这些知识大家可以类比关系数据库的相关知识。

992
来自专栏哲学驱动设计

Rafy 框架 - 通用查询条件(CommonQueryCriteria)

在应用开发过程中,有 80% 的场景下,开发者所需要的实体查询,查询条件中其实都是一些简单的属性匹配,又或是一些属性匹配的简单组合。Rafy 为这样的场景提供了...

2007
来自专栏西枫里博客

ThinkPHP使用数组条件进行查询之同一字段多个条件

对同一表中多个字段的查询,在thinkPHP中使用数组条件进行查询,有三个好处,第一可以批量设置多个查询字段,第二可以设置多个查询条件,第三结构化你的代码,让代...

542
来自专栏我是攻城师

Solr中如何使用游标进行深度分页查询

3106
来自专栏沃趣科技

MySQL排序内部原理探秘

一、我们要解决什么问题 二、排序,排序,排序 三、索引优化排序 四、排序模式 4.1实际trace结果 4.2排序模式概览 4.2.1回表排序模式 4.2.2不...

3466
来自专栏积累沉淀

大型数据库技术1

什么是数据库? 在计算机系统中按照一定的数据模型组织、存储和使用相互关联的数据集合。 数据模型 通常是由数据结构、数据操作、完整性约束3部分组成。    ...

1896
来自专栏应兆康的专栏

Python Web - Flask笔记6

mysql级别的外键,还不够ORM,必须拿到一个表的外键,然后通过这个外键再去另外一张表中查找,这样太麻烦了。SQLAlchemy提供了一个relationsh...

601
来自专栏JackeyGao的博客

Django小技巧08: Blank or Null

Django Model API 中提供了blank和null两个参数, 非常容易混淆。当我第一次使用 Django 的时候, 总是不能恰当的使用这两个参数。

513

扫码关注云+社区