第 8 章 继承映射(Inheritance Mappings)
8.1. 三种策略
Hibernate支持三种不同的基本继承映射策略。
每棵类继承树使用一个表(table per class hierarchy)
每个子类一个表(table per subclass)
每个具体类一个表(table per concrete class)(有一些限制)
甚至在一棵继承关系书中对不同的分支使用不同的映射策略也是可能的。但是和“每个具体类一个表”的映射有一样的限制。Hibernate不支持把<subclass>映射与<joined-subclass>在同一个<class> 元素中混合使用。
假设我们有一个Payment接口,有不同的实现:CreditCardPayment, CashPayment, ChequePayment。“继承数共享一个表”的映射是这样的:
<class name="Payment" table="PAYMENT">
<id name="id" type="long" column="PAYMENT_ID">
<generator class="native"/>
</id>
<discriminator column="PAYMENT_TYPE" type="string"/>
<property name="amount" column="AMOUNT"/>
...
<subclass name="CreditCardPayment" discriminator-value="CREDIT">
...
</subclass>
<subclass name="CashPayment" discriminator-value="CASH">
...
</subclass>
<subclass name="ChequePayment" discriminator-value="CHEQUE">
...
</subclass>
</class>
只需要一个表。这种映射策略由一个大限制:子类定义的字段不能有NOT NULL限制。
“每个子类一个表”的映射是这样的:
<class name="Payment" table="PAYMENT">
<id name="id" type="long" column="PAYMENT_ID">
<generator class="native"/>
</id>
<property name="amount" column="AMOUNT"/>
...
<joined-subclass name="CreditCardPayment" table="CREDIT_PAYMENT">
<key column="PAYMENT_ID"/>
...
</joined-subclass>
<joined-subclass name="CashPayment" table="CASH_PAYMENT">
<key column="PAYMENT_ID"/>
...
</joined-subclass>
<joined-subclass name="ChequePayment" table="CHEQUE_PAYMENT">
<key column="PAYMENT_ID"/>
...
</joined-subclass>
</class>
需要四个表。三个子类表通过主键和超类表关联(所以实际上关系模型是一对一关联)。
注意Hibernate的“每子类一表”的实现并不需要一个特别的辨认字段。其他的对象/关系数据库映射工具使用另一种“每子类一表”实现,需要在超类表中有一个类型辨认字段。Hibernate的这种实现更加困难,但是从关系(数据库)的角度来看,这样做更加正确。
对这两种映射策略来说,指向Payment的关联是使用<many-to-one>进行映射的。
<many-to-one name="payment"
column="PAYMENT"
class="Payment"/>
“每个具体类一个表”的策略非常不同
<class name="CreditCardPayment" table="CREDIT_PAYMENT">
<id name="id" type="long" column="CREDIT_PAYMENT_ID">
<generator class="native"/>
</id>
<property name="amount" column="CREDIT_AMOUNT"/>
...
</class>
<class name="CashPayment" table="CASH_PAYMENT">
<id name="id" type="long" column="CASH_PAYMENT_ID">
<generator class="native"/>
</id>
<property name="amount" column="CASH_AMOUNT"/>
...
</class>
<class name="ChequePayment" table="CHEQUE_PAYMENT">
<id name="id" type="long" column="CHEQUE_PAYMENT_ID">
<generator class="native"/>
</id>
<property name="amount" column="CHEQUE_AMOUNT"/>
...
</class>