Movatterモバイル変換


[0]ホーム

URL:


Hibernate.orgCommunity Documentation

Chapter 10. Inheritance mapping

Table of Contents

10.1. The three strategies
10.1.1. Table per class hierarchy
10.1.2. Table per subclass
10.1.3. Table per subclass: using a discriminator
10.1.4. Mixing table per class hierarchy with table per subclass
10.1.5. Table per concrete class
10.1.6. Table per concrete class using implicit polymorphism
10.1.7. Mixing implicit polymorphism with other inheritance mappings
10.2. Limitations

10.1. The three strategies

Hibernate supports the three basic inheritance mapping strategies:

In addition, Hibernate supports a fourth, slightly different kind of polymorphism:

It is possible to use different mapping strategies for different branches of the same inheritance hierarchy. You can then make use of implicit polymorphism to achieve polymorphism across the whole hierarchy. However, Hibernate does not support mixing<subclass>,<joined-subclass> and<union-subclass> mappings under the same root<class> element. It is possible to mix together the table per hierarchy and table per subclass strategies under the the same<class> element, by combining the<subclass> and<join> elements (see below for an example).

It is possible to definesubclass,union-subclass, andjoined-subclass mappings in separate mapping documents directly beneathhibernate-mapping. This allows you to extend a class hierarchy by adding a new mapping file. You must specify anextends attribute in the subclass mapping, naming a previously mapped superclass. Previously this feature made the ordering of the mapping documents important. Since Hibernate3, the ordering of mapping files is irrelevant when using the extends keyword. The ordering inside a single mapping file still needs to be defined as superclasses before subclasses.

 <hibernate-mapping>     <subclass name="DomesticCat" extends="Cat" discriminator-value="D">          <property name="name" type="string"/>     </subclass> </hibernate-mapping>

Suppose we have an interfacePayment with the implementorsCreditCardPayment,CashPayment, andChequePayment. The table per hierarchy mapping would display in the following way:

<class name="Payment" table="PAYMENT">    <id name="id" type="long" column="PAYMENT_ID">        <generator/>    </id>    <discriminator column="PAYMENT_TYPE" type="string"/>    <property name="amount" column="AMOUNT"/>    ...    <subclass name="CreditCardPayment" discriminator-value="CREDIT">        <property name="creditCardType" column="CCTYPE"/>        ...    </subclass>    <subclass name="CashPayment" discriminator-value="CASH">        ...    </subclass>    <subclass name="ChequePayment" discriminator-value="CHEQUE">        ...    </subclass></class>

Exactly one table is required. There is a limitation of this mapping strategy: columns declared by the subclasses, such asCCTYPE, cannot haveNOT NULL constraints.

A table per subclass mapping looks like this:

<class name="Payment" table="PAYMENT">    <id name="id" type="long" column="PAYMENT_ID">        <generator/>    </id>    <property name="amount" column="AMOUNT"/>    ...    <joined-subclass name="CreditCardPayment" table="CREDIT_PAYMENT">        <key column="PAYMENT_ID"/>        <property name="creditCardType" column="CCTYPE"/>        ...    </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>

Four tables are required. The three subclass tables have primary key associations to the superclass table so the relational model is actually a one-to-one association.

Hibernate's implementation of table per subclass does not require a discriminator column. Other object/relational mappers use a different implementation of table per subclass that requires a type discriminator column in the superclass table. The approach taken by Hibernate is much more difficult to implement, but arguably more correct from a relational point of view. If you want to use a discriminator column with the table per subclass strategy, you can combine the use of<subclass> and<join>, as follows:

<class name="Payment" table="PAYMENT">    <id name="id" type="long" column="PAYMENT_ID">        <generator/>    </id>    <discriminator column="PAYMENT_TYPE" type="string"/>    <property name="amount" column="AMOUNT"/>    ...    <subclass name="CreditCardPayment" discriminator-value="CREDIT">        <join table="CREDIT_PAYMENT">            <key column="PAYMENT_ID"/>            <property name="creditCardType" column="CCTYPE"/>            ...        </join>    </subclass>    <subclass name="CashPayment" discriminator-value="CASH">        <join table="CASH_PAYMENT">            <key column="PAYMENT_ID"/>            ...        </join>    </subclass>    <subclass name="ChequePayment" discriminator-value="CHEQUE">        <join table="CHEQUE_PAYMENT" fetch="select">            <key column="PAYMENT_ID"/>            ...        </join>    </subclass></class>

The optionalfetch="select" declaration tells Hibernate not to fetch theChequePayment subclass data using an outer join when querying the superclass.

You can even mix the table per hierarchy and table per subclass strategies using the following approach:

<class name="Payment" table="PAYMENT">    <id name="id" type="long" column="PAYMENT_ID">        <generator/>    </id>    <discriminator column="PAYMENT_TYPE" type="string"/>    <property name="amount" column="AMOUNT"/>    ...    <subclass name="CreditCardPayment" discriminator-value="CREDIT">        <join table="CREDIT_PAYMENT">            <property name="creditCardType" column="CCTYPE"/>            ...        </join>    </subclass>    <subclass name="CashPayment" discriminator-value="CASH">        ...    </subclass>    <subclass name="ChequePayment" discriminator-value="CHEQUE">        ...    </subclass></class>

For any of these mapping strategies, a polymorphic association to the rootPayment class is mapped using<many-to-one>.

<many-to-one name="payment" column="PAYMENT_ID"/>

There are two ways we can map the table per concrete class strategy. First, you can use<union-subclass>.

<class name="Payment">    <id name="id" type="long" column="PAYMENT_ID">        <generator/>    </id>    <property name="amount" column="AMOUNT"/>    ...    <union-subclass name="CreditCardPayment" table="CREDIT_PAYMENT">        <property name="creditCardType" column="CCTYPE"/>        ...    </union-subclass>    <union-subclass name="CashPayment" table="CASH_PAYMENT">        ...    </union-subclass>    <union-subclass name="ChequePayment" table="CHEQUE_PAYMENT">        ...    </union-subclass></class>

Three tables are involved for the subclasses. Each table defines columns for all properties of the class, including inherited properties.

The limitation of this approach is that if a property is mapped on the superclass, the column name must be the same on all subclass tables. The identity generator strategy is not allowed in union subclass inheritance.The primary key seed has to be shared across all unioned subclassesof a hierarchy.

If your superclass is abstract, map it withabstract="true". If it is not abstract, an additional table (it defaults toPAYMENT in the example above), is needed to hold instances of the superclass.

An alternative approach is to make use of implicit polymorphism:

<class name="CreditCardPayment" table="CREDIT_PAYMENT">    <id name="id" type="long" column="CREDIT_PAYMENT_ID">        <generator/>    </id>    <property name="amount" column="CREDIT_AMOUNT"/>    ...</class><class name="CashPayment" table="CASH_PAYMENT">    <id name="id" type="long" column="CASH_PAYMENT_ID">        <generator/>    </id>    <property name="amount" column="CASH_AMOUNT"/>    ...</class><class name="ChequePayment" table="CHEQUE_PAYMENT">    <id name="id" type="long" column="CHEQUE_PAYMENT_ID">        <generator/>    </id>    <property name="amount" column="CHEQUE_AMOUNT"/>    ...</class>

Notice that thePayment interface is not mentioned explicitly. Also notice that properties ofPayment are mapped in each of the subclasses. If you want to avoid duplication, consider using XML entities (for example,[ <!ENTITY allproperties SYSTEM "allproperties.xml"> ] in theDOCTYPE declaration and%allproperties; in the mapping).

The disadvantage of this approach is that Hibernate does not generate SQLUNIONs when performing polymorphic queries.

For this mapping strategy, a polymorphic association toPayment is usually mapped using<any>.

<any name="payment" meta-type="string" id-type="long">    <meta-value value="CREDIT"/>    <meta-value value="CASH"/>    <meta-value value="CHEQUE"/>    <column name="PAYMENT_CLASS"/>    <column name="PAYMENT_ID"/></any>

Since the subclasses are each mapped in their own<class> element, and sincePayment is just an interface), each of the subclasses could easily be part of another inheritance hierarchy. You can still use polymorphic queries against thePayment interface.

<class name="CreditCardPayment" table="CREDIT_PAYMENT">    <id name="id" type="long" column="CREDIT_PAYMENT_ID">        <generator/>    </id>    <discriminator column="CREDIT_CARD" type="string"/>    <property name="amount" column="CREDIT_AMOUNT"/>    ...    <subclass name="MasterCardPayment" discriminator-value="MDC"/>    <subclass name="VisaPayment" discriminator-value="VISA"/></class><class name="NonelectronicTransaction" table="NONELECTRONIC_TXN">    <id name="id" type="long" column="TXN_ID">        <generator/>    </id>    ...    <joined-subclass name="CashPayment" table="CASH_PAYMENT">        <key column="PAYMENT_ID"/>        <property name="amount" column="CASH_AMOUNT"/>        ...    </joined-subclass>    <joined-subclass name="ChequePayment" table="CHEQUE_PAYMENT">        <key column="PAYMENT_ID"/>        <property name="amount" column="CHEQUE_AMOUNT"/>        ...    </joined-subclass></class>

Once again,Payment is not mentioned explicitly. If we execute a query against thePayment interface, for examplefrom Payment, Hibernate automatically returns instances ofCreditCardPayment (and its subclasses, since they also implementPayment),CashPayment andChequePayment, but not instances ofNonelectronicTransaction.

10.2. Limitations

There are limitations to the "implicit polymorphism" approach to the table per concrete-class mapping strategy. There are somewhat less restrictive limitations to<union-subclass> mappings.

The following table shows the limitations of table per concrete-class mappings, and of implicit polymorphism, in Hibernate.

Table 10.1. Features of inheritance mappings

Inheritance strategyPolymorphic many-to-onePolymorphic one-to-onePolymorphic one-to-manyPolymorphic many-to-manyPolymorphicload()/get()Polymorphic queriesPolymorphic joinsOuter join fetching
table per class-hierarchy<many-to-one><one-to-one><one-to-many><many-to-many>s.get(Payment.class, id)from Payment pfrom Order o join o.payment psupported
table per subclass<many-to-one><one-to-one><one-to-many><many-to-many>s.get(Payment.class, id)from Payment pfrom Order o join o.payment psupported
table per concrete-class (union-subclass)<many-to-one><one-to-one><one-to-many> (forinverse="true" only)<many-to-many>s.get(Payment.class, id)from Payment pfrom Order o join o.payment psupported
table per concrete class (implicit polymorphism)<any>not supportednot supported<many-to-any>s.createCriteria(Payment.class).add( Restrictions.idEq(id) ).uniqueResult()from Payment pnot supportednot supported



[8]ページ先頭

©2009-2025 Movatter.jp