繼承 - Table per concrete class with unions


繼 承 - 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
        (?, ?, ?)

由於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)

而觀察利用多型特性查詢時的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_

相對於兩次的SQL進入資料庫,利用子查詢在同一個SQL語句中完成所有的資料查詢,會有可能有效能上的改進,而使用此方法,對往後若有多型查詢的需求時,修改上會比較方便。