今天这篇博客,说的是hibernate的继承映射。
一、以前使用过继承映射吗?
刚听到继承映射的时候,不知道是怎么一回事。视频看完,哦,原来我使用过。没有学习过ORM之类知识的孩子们,如果是第一次听说,不要担心,你们一定使用过,只是不知道它用过这样一个名称而已。看下面的表:
这样的表结构,是不是很熟悉的。这就是继承映射的一种。
特点:
1、表中存放了几种不同类型的数据
2、他们用“Type”字段来区分。
3、字段有公用的,有特殊的。
公用的就是:name,sex ,但是有些字段是针对某种数据而存在的,所以数据库中有写字典为“空”。例如:heigth 是针对“小鸟鸟”,而weight 是针对“小猪猪”的。
继承映射不光只有这一种形式,我们来看看继承映射的形式。
二、继承映射
什么继承映射?要说继承映射之前,得先说说继承映射的由来。大家知道在面向对象的程序领域中,类与类之间是有继承关系的,例如Java世界中只需要extends关键字就可以确定这两个类的父子关系,但是在关系数据库的世界中,表与表之间没有任何关键字可以明确指明这两张表的父子关系,表与表是没有继承关系这样的说法的。为了将程序领域中的继承关系反映到数据中,Hibernate为我们提供了三种方案,分别是:
1:一颗继承树一张表。
2:一个类对应一张表。
3:每个具体子类使用一张表。
我们先看 继承关系类图,这就是一颗继承树。
通过这颗树,来理解这三种表现形式。
首先是第一种:使用一张表表示所有继承体系下的类的属性的并集。
这种策略是使用<subclass>标签来实现的。因为类继承体系下会有许多个子类,要把多个类的信息存放在一张表中,必须有某种机制来区分哪些记录是属于哪个类的。Hibernate中的这种机制就是,在表中添加一个字段,用这个字段的值来进行区分。在表中添加这个标示列使用<discriminator>标签来实现。这也是第一篇中提到的“例子”。Animal,Pig,Bird都映射到一张表中。
hbm.xml 如下:
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.bjpowernode.hibernate">
<span style="color:#FF0000;"><class name="Animal</span>" table="t_animal" lazy="false">
<id name="id">
<generator class="native"/>
</id>
<span style="color:#FF0000;"><discriminator</span> column="type" type="string"/>
<property name="name"/>
<property name="sex"/>
<span style="color:#FF0000;"><subclass</span> name="Pig" discriminator-value="P">
<property name="weight"/>
</subclass>
<span style="color:#FF6666;"><subclass </span>name="Bird" discriminator-value="B">
<property name="height"/>
</subclass>
</class>
</hibernate-mapping>
其次是第二种:一个类一张表:上图中继承树,就可以被映射成三个表;
这种策略是使用<joined-subclass>标签来定义子类的。父类、子类都对应一张数据库表。在父类对应的数据库表中,它存储了所有记录的公共信息,实际上该父类对应的表会包含所有的记录,包括父类和子类的记录;在子类对应的数据库表中,这个表只定义了子类中所特有的属性映射的字段。子类对应的数据表与父类对应的数据表,通过一对一主键关联的方式关联起来。
<?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.bjpowernode.hibernate">
<<span style="color:#FF0000;">class name="Animal"</span> table="t_animal">
<id name="id">
<generator class="native"/>
</id>
<property name="name"/>
<property name="sex"/>
<span style="color:#FF0000;"><joined-subclass</span> name="Pig" table="t_pig">
<key column="pid"/>
<property name="weight"/>
</joined-subclass>
<span style="color:#FF0000;"><joined-subclass</span> name="Bird" table="t_bird">
<key column="bid"/>
<property name="height"/>
</joined-subclass>
</class>
</hibernate-mapping>
最后是每个具体子类一张表:每一个子类对应的数据库表都包含了父类的信息,并且包含了自己独有的属性。每个子类对应一张表,而且这个表的信息是完备的,即包含了所有从父类继承下来的属性映射的字段。这种策略是使用<union-subclass>标签来定义子类的。
<span style="font-family:KaiTi_GB2312;font-size:18px;"><?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.bjpowernode.hibernate">
<<span style="color:#FF0000;">class name</span>="Animal" table="t_animal" <span style="color:#FF0000;">abstract="true</span>">
<id name="id">
<generator class="assigned"/>
</id>
<property name="name"/>
<property name="sex"/>
<span style="color:#FF0000;"><union-subclass</span> name="Pig" table="t_pig">
<property name="weight"/>
</union-subclass>
<span style="color:#FF0000;"><union-subclass</span> name="Bird" table="t_bird">
<property name="height"/>
</union-subclass>
</class>
</hibernate-mapping></span>
三种映射形式简单对比
[3]包含重复字段;
[3]若查询父类需查所有子类表;
[3]若父类属性变化需要修改所有子类对应的表;
一句话:具体情况具体分析。