Hibernate.org Community Documentation

- Zurück
- Weiter

## Kapitel 10. Inheritance mapping

## 10.1. The three strategies

Hibernate unterstützt drei grundlegende Mapping-Strategien der Vererbung:

- "Tabelle-pro-Klasse"-Hierarchie

- table per subclass

- "Tabelle-pro-konkrete-Klasse"

Desweiteren unterstützt Hibernate eine vierte, etwas andere Art der Polymorphie:

- implizite Polymorphie

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 define `subclass`, `union-subclass`, and `joined-subclass` mappings in separate mapping documents directly beneath `hibernate-mapping`. This allows you to extend a class hierarchy by adding a new mapping file. You must specify an `extends` 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

    >

### 10.1.1. "Tabelle-pro-Klasse"-Hierarchie

Suppose we have an interface `Payment` with the implementors `CreditCardPayment`, `CashPayment`, and `ChequePayment`. 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 class="native"/>

        </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 as `CCTYPE`, cannot have `NOT NULL` constraints.

### 10.1.2. "Tabelle-pro-Subklasse"

A table per subclass mapping looks like this:

    <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"/>

            <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.

### 10.1.3. Table per subclass: using a discriminator

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 class="native"/>

        </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

    >

Durch die optionale `fetch="select"`-Deklaration ruft Hibernate die `ChequePayment`-Subklassendaten unter Verwendung eines äußeren Verbunds (sog. "outer Join") bei Anfragen an die Superklasse nicht auf.

### 10.1.4. Das Mischen der "Tabelle-pro-Klasse"-Hierarchie mit "Tabelle-pro-Subklasse"

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 class="native"/>

        </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

    >

Bei allen diesen Mapping-Strategien wird eine polymorphe Assoziation zur Stamm-`Payment`-Klasse mittels `<many-to-one>` gemappt.

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

### 10.1.5. "Tabelle-pro-konkrete-Klasse"

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 class="sequence"/>

        </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

    >

Drei Tabellen sind für die Subklassen involviert. Jede Tabelle definiert Spalten für alle Properties der Klasse, einschließlich vererbter 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 subclasses of a hierarchy.

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

### 10.1.6. Table per concrete class using implicit polymorphism

Alternativ kann implizite Polymorphie angewendet werden:

    <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

    >

Notice that the `Payment` interface is not mentioned explicitly. Also notice that properties of `Payment` 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 the `DOCTYPE` declaration and `&allproperties;` in the mapping).

The disadvantage of this approach is that Hibernate does not generate SQL `UNION`s when performing polymorphic queries.

Bei dieser Mapping-Strategie wird in der Regel eine polymorphe Assoziation zu `Payment` mittels `<any>` gemappt.

    <any name="payment" meta-type="string" id-type="long">

        <meta-value value="CREDIT" class="CreditCardPayment"/>

        <meta-value value="CASH" class="CashPayment"/>

        <meta-value value="CHEQUE" class="ChequePayment"/>

        <column name="PAYMENT_CLASS"/>

        <column name="PAYMENT_ID"/>

    </any

    >

### 10.1.7. Das Mischen impliziter Polymorphie mit anderen Vererbungsmappings

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

    <class name="CreditCardPayment" table="CREDIT_PAYMENT">

        <id name="id" type="long" column="CREDIT_PAYMENT_ID">

            <generator class="native"/>

        </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 class="native"/>

        </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 the `Payment` interface, for example `from Payment`, Hibernate automatically returns instances of `CreditCardPayment` (and its subclasses, since they also implement `Payment`), `CashPayment` and `ChequePayment`, but not instances of `NonelectronicTransaction`.

## 10.2. Einschränkungen

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.

Tabelle 10.1. Features von Vererbungsmappings

Vererbungsstrategie | Polymorphic many-to-one | Polymorphes "One-to-One" | Polymorphes "One-to-Many" | Polymorphes "Many-to-Many" | Polymorphes `load()/get()` | Polymorphe Anfragen | Polymorphe Verknüpfungen | Outer 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 p` | `from Order o join o.payment p` | supported
table per subclass | `<many-to-one>` | `<one-to-one>` | `<one-to-many>` | `<many-to-many>` | `s.get(Payment.class, id)` | `from Payment p` | `from Order o join o.payment p` | supported
Tabelle-pro-konkrete-Klasse (Union-Subklasse) | `<many-to-one>` | `<one-to-one>` | `<one-to-many>` (for `inverse="true"` only) | `<many-to-many>` | `s.get(Payment.class, id)` | `from Payment p` | `from Order o join o.payment p` | supported
table per concrete class (implicit polymorphism) | `<any>` | not supported | not supported | `<many-to-any>` | `s.createCriteria(Payment.class).add( Restrictions.idEq(id) ).uniqueResult()` | `from Payment p` | not supported | not supported

Copyright © 2004 Red Hat, Inc.

- ZurückKapitel 9. Komponenten-Mapping
- Nach oben
- Zum Anfang
- WeiterKapitel 11. Das Arbeiten mit Objekten