ITEEDU

Hibernate Gossip: 继承 - Table per class hierarchy

接续 上一个主题,Table per concrete class的继承映像方式是最简单,但没有效率(例如查询同为User类型时,需要两次SQL)且不易管理的映像方式,来看看继承关系映像至关系型数据库 的第二种方式:Table per class hierarchy。这种方式使用一个表格储存同一个继承阶层的所有类别,并使用额外的字段来表示所记录的是哪一个子类别的数据。

具体来说,对于继承User类别的DefaultUser及PowerUser,可以设计以下的表格来储存数据:
Table per class hierarchy

可以使用以下的SQL来建立表格:
CREATE TABLE user (
    id INT(11) NOT NULL auto_increment PRIMARY KEY,
    userType VARCHAR(50) NOT NULL,
    name VARCHAR(100) NOT NULL default '',
    someProperty VARCHAR(100),
    otherProperty VARCHAR(100)
);
现在所决定的是,如果要储存的数据是来自DefalutUser,则在userType记下"Default",如果储存的数据来PowerUser,则 在userType记下"Power",由userType就可以在数据从数据库取回时,决定其该封装为DefaultUser或是PowerUser, 在使用Hibernate的话,这要在映射文件中使用<discriminator>等相关标签来定义,例如:
User.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>

<class name="onlyfun.caterpillar.User" table="user">

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

<discriminator column="userType" type="java.lang.String"/>

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

<subclass name="onlyfun.caterpillar.DefaultUser"
discriminator-value="Default">
<property name="someProperty"
column="someProperty"
type="java.lang.String"/>
</subclass>

<subclass name="onlyfun.caterpillar.PowerUser"
discriminator-value="Power">
<property name="otherProperty"
column="otherProperty"
type="java.lang.String"/>
</subclass>
</class>

</hibernate-mapping>

当然,别忘了在hibernate.cfg.xml 中指定映像文件:
hibernate.cfg.xml
<?xml version="1.0" encoding="utf-8"?> 
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">

<hibernate-configuration>

<session-factory>
....

<!-- 物件與資料庫表格映射文件 -->
<mapping resource="onlyfun/caterpillar/User.hbm.xml"/>

</session-factory>

</hibernate-configuration>

使用 上一个主题 中的储存程序的话,则Hibernate会使用以下的SQL来储存数据:
Hibernate: insert into user (name, otherProperty, userType) values (?, ?, 'Power')
Hibernate: insert into user (name, someProperty, userType) values (?, ?, 'Default')
而实际上数据表会储存以下的内容:
+----+-------------+-------------+-------------------+------------------+
| id    | userType | name        | someProperty | otherProperty |
+----+-------------+-------------+-------------------+------------------+
|  1    | Power       | caterpillar | NULL               | Bla...Bla...        |
|  2    | Default     | Bush         | hu....hu...         | NULL               |
+----+-------------+-------------+-------------------+-------------------+


缺点就是,因子类别属性的不同,对映储存时会有许多字段没有数据,但查询效率较好,例如查询User类型的数据时,只需一次SQL,如使用 上一个主题 中的查询程序时,Hibernate会使用以下的SQL进行查询:
Hibernate:
select user0_.id as id, user0_.name as name0_, user0_.someProperty as
someProp4_0_, user0_.otherProperty as otherPro5_0_, user0_.userType as
userType from user user0_