續 繼 承 - Table per concrete class with implicit polymorphism,除了分別為兩個子類別撰寫個別的HBM檔案之外,您可以在一個HBM檔案中,將父類別與子類別的屬性對應撰寫在一起,直接以實例來說明:
- 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 package="onlyfun.caterpillar">
<!-- abstract 表明User是抽象的,無需對應至任何表格 -->
<class name="User" abstract="true">
<id name="id">
<generator class="increment"/>
</id>
<!-- 從父類別繼承下來的共同屬性 -->
<property name="name"/>
<!-- 子類別的新增屬性 -->
<union-subclass name="DefaultUser" table="defaultuser">
<property name="someProperty"/>
</union-subclass>
<!-- 子類別的新增屬性 -->
<union-subclass name="PowerUser" table="poweruser">
<property name="otherProperty"/>
</union-subclass>
</class>
</hibernate-mapping>
可以看到,現在您不用在兩個HBM檔中,針對相同的屬性撰寫重複的定義內容,而hibernate.cfg.xml中,只要設定User.hbm.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>
除了設定檔上的簡化之外,觀察 繼 承 - Table per concrete class with implicit polymorphism 中同一程式新增資料時的SQL:
Hibernate:
select
max(ids_.id)
from
( select
id
from
defaultuser
union
select
id
from
poweruser
) ids_
Hibernate:
insert
into
poweruser
(name, otherProperty, id)
values
(?, ?, ?)
Hibernate:
insert
into
defaultuser
(name, someProperty, id)
values
(?, ?, ?)
select
max(ids_.id)
from
( select
id
from
defaultuser
union
select
id
from
poweruser
) ids_
Hibernate:
insert
into
poweruser
(name, otherProperty, id)
values
(?, ?, ?)
Hibernate:
insert
into
defaultuser
(name, someProperty, id)
values
(?, ?, ?)
由於generator設定為increment,在新增資料之前,先確定了兩個表格的id值最大為何,再分別遞增id並儲存物件至表格之中,所以您直接查詢資料庫中的表格,會發現id值有前後遞增的關係:
mysql> select * from defaultuser;
+----+------+--------------+
| id | name | someProperty |
+----+------+--------------+
| 2 | Bush | hu....hu... |
+----+------+--------------+
1 row in set (0.00 sec)
mysql> select * from poweruser;
+----+-------------+---------------+
| id | name | otherProperty |
+----+-------------+---------------+
| 1 | caterpillar | Bla...Bla... |
+----+-------------+---------------+
1 row in set (0.00 sec)
+----+------+--------------+
| id | name | someProperty |
+----+------+--------------+
| 2 | Bush | hu....hu... |
+----+------+--------------+
1 row in set (0.00 sec)
mysql> select * from poweruser;
+----+-------------+---------------+
| id | name | otherProperty |
+----+-------------+---------------+
| 1 | caterpillar | Bla...Bla... |
+----+-------------+---------------+
1 row in set (0.00 sec)
而觀察利用多型特性查詢時的SQL,可以看到利用了子查詢在一個SQL語句中完成查詢動作:
Hibernate:
select
user0_.id as id0_,
user0_.name as name0_,
user0_.someProperty as someProp1_1_,
user0_.otherProperty as otherPro1_2_,
user0_.clazz_ as clazz_
from
( select
id,
null as otherProperty,
name,
someProperty,
1 as clazz_
from
defaultuser
union
select
id,
otherProperty,
name,
null as someProperty,
2 as clazz_
from
poweruser
) user0_
select
user0_.id as id0_,
user0_.name as name0_,
user0_.someProperty as someProp1_1_,
user0_.otherProperty as otherPro1_2_,
user0_.clazz_ as clazz_
from
( select
id,
null as otherProperty,
name,
someProperty,
1 as clazz_
from
defaultuser
union
select
id,
otherProperty,
name,
null as someProperty,
2 as clazz_
from
poweruser
) user0_
相對於兩次的SQL進入資料庫,利用子查詢在同一個SQL語句中完成所有的資料查詢,會有可能有效能上的改進,而使用此方法,對往後若有多型查詢的需求時,修改上會比較方便。