|
Hibernate example source code file (inheritance_mapping.xml)
This example Hibernate source code file (inheritance_mapping.xml) is included in the DevDaily.com
"Java Source Code
Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.
The Hibernate inheritance_mapping.xml source code
<?xml version='1.0' encoding="UTF-8"?>
<!--
~ Hibernate, Relational Persistence for Idiomatic Java
~
~ Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
~ indicated by the @author tags or express copyright attribution
~ statements applied by the authors. All third-party contributions are
~ distributed under license by Red Hat Middleware LLC.
~
~ This copyrighted material is made available to anyone wishing to use, modify,
~ copy, or redistribute it subject to the terms and conditions of the GNU
~ Lesser General Public License, as published by the Free Software Foundation.
~
~ This program is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
~ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
~ for more details.
~
~ You should have received a copy of the GNU Lesser General Public License
~ along with this distribution; if not, write to:
~ Free Software Foundation, Inc.
~ 51 Franklin Street, Fifth Floor
~ Boston, MA 02110-1301 USA
-->
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
<!ENTITY % BOOK_ENTITIES SYSTEM "../HIBERNATE_-_Relational_Persistence_for_Idiomatic_Java.ent">
%BOOK_ENTITIES;
]>
<chapter id="inheritance">
<title>Inheritance mapping
<section id="inheritance-strategies" revision="3">
<title>The three strategies
<para>
Hibernate supports the three basic inheritance mapping strategies:
</para>
<itemizedlist>
<listitem>
<para>
table per class hierarchy
</para>
</listitem>
<listitem>
<para>
table per subclass
</para>
</listitem>
<listitem>
<para>
table per concrete class
</para>
</listitem>
</itemizedlist>
<para>
In addition, Hibernate supports a fourth, slightly different kind of
polymorphism:
</para>
<itemizedlist>
<listitem>
<para>
implicit polymorphism
</para>
</listitem>
</itemizedlist>
<para>
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 <literal><subclass>,
<literal><joined-subclass> and
<literal><union-subclass> mappings under the same root
<literal><class> element. It is possible to mix together
the table per hierarchy and table per subclass strategies under the
the same <literal><class> element, by combining the
<literal><subclass> and <join>
elements (see below for an example).
</para>
<para>
It is possible to define <literal>subclass, union-subclass,
and <literal>joined-subclass mappings in separate mapping documents directly beneath
<literal>hibernate-mapping. This allows you to extend a class hierarchy by adding
a new mapping file. You must specify an <literal>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.
</para>
<programlisting role="XML">
<section id="inheritance-tableperclass" >
<title>Table per class hierarchy
<para>
Suppose we have an interface <literal>Payment with the implementors
<literal>CreditCardPayment, CashPayment,
and <literal>ChequePayment. The table per hierarchy mapping would
display in the following way:
</para>
<programlisting role="XML">
<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>]]>
<para>
Exactly one table is required. There is a limitation of this mapping
strategy: columns declared by the subclasses, such as <literal>CCTYPE,
cannot have <literal>NOT NULL constraints.
</para>
</section>
<section id="inheritance-tablepersubclass">
<title>Table per subclass
<para>
A table per subclass mapping looks like this:
</para>
<programlisting role="XML">
<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>]]>
<para>
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.
</para>
</section>
<section id="inheritance-tablepersubclass-discriminator" revision="2">
<title>Table per subclass: using a discriminator
<para>
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 <literal><subclass> and
<literal><join>, as follows:
</para>
<programlisting role="XML">
<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>]]>
<para>
The optional <literal>fetch="select" declaration tells Hibernate
not to fetch the <literal>ChequePayment subclass data using an
outer join when querying the superclass.
</para>
</section>
<section id="inheritance-mixing-tableperclass-tablepersubclass">
<title>Mixing table per class hierarchy with table per subclass
<para>
You can even mix the table per hierarchy and table per subclass strategies
using the following approach:
</para>
<programlisting role="XML">
<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>]]>
<para>
For any of these mapping strategies, a polymorphic association to the root
<literal>Payment class is mapped using
<literal><many-to-one>.
</para>
<programlisting role="XML">]]>
</section>
<section id="inheritance-tableperconcrete" revision="2">
<title>Table per concrete class
<para>
There are two ways we can map the table per concrete class
strategy. First, you can use <literal><union-subclass>.
</para>
<programlisting role="XML">
<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>]]>
<para>
Three tables are involved for the subclasses. Each table defines columns for
all properties of the class, including inherited properties.
</para>
<para>
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.
</para>
<para>
If your superclass is abstract, map it with <literal>abstract="true".
If it is not abstract, an additional table (it defaults to
<literal>PAYMENT in the example above), is needed to hold instances
of the superclass.
</para>
</section>
<section id="inheritance-tableperconcreate-polymorphism">
<title>Table per concrete class using implicit polymorphism
<para>
An alternative approach is to make use of implicit polymorphism:
</para>
<programlisting role="XML">
<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>]]>
<para>
Notice that the <literal>Payment interface
is not mentioned explicitly. Also notice that properties of <literal>Payment are
mapped in each of the subclasses. If you want to avoid duplication, consider
using XML entities
(for example, <literal>[ <!ENTITY allproperties SYSTEM "allproperties.xml"> ]
in the <literal>DOCTYPE declaration and
<literal>&allproperties; in the mapping).
</para>
<para>
The disadvantage of this approach is that Hibernate does not generate SQL
<literal>UNIONs when performing polymorphic queries.
</para>
<para>
For this mapping strategy, a polymorphic association to <literal>Payment
is usually mapped using <literal><any>.
</para>
<programlisting role="XML">
<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>]]>
</section>
<section id="inheritance-mixingpolymorphism">
<title>Mixing implicit polymorphism with other inheritance mappings
<para>
Since the subclasses
are each mapped in their own <literal><class> element, and since
<literal>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 <literal>Payment interface.
</para>
<programlisting role="XML">
<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>]]>
<para>
Once again, <literal>Payment is not mentioned explicitly. If we
execute a query against the <literal>Payment interface, for
example <literal>from Payment, Hibernate
automatically returns instances of <literal>CreditCardPayment
(and its subclasses, since they also implement <literal>Payment),
<literal>CashPayment and ChequePayment, but
not instances of <literal>NonelectronicTransaction.
</para>
</section>
</section>
<section id="inheritance-limitations">
<title>Limitations
<para>
There are limitations to the "implicit polymorphism" approach to
the table per concrete-class mapping strategy. There are somewhat less
restrictive limitations to <literal><union-subclass>
mappings.
</para>
<para>
The following table shows the limitations of table per concrete-class
mappings, and of implicit polymorphism, in Hibernate.
</para>
<table frame="topbot">
<title>Features of inheritance mappings
<tgroup cols='9' align='left' colsep='1' rowsep='1'>
<colspec colname='c1' colwidth="1*"/>
<colspec colname='c2' colwidth="1*"/>
<colspec colname='c3' colwidth="1*"/>
<colspec colname='c4' colwidth="1*"/>
<colspec colname='c5' colwidth="1*"/>
<colspec colname='c6' colwidth="1*"/>
<colspec colname='c7' colwidth="1*"/>
<colspec colname='c8' colwidth="1*"/>
<colspec colname='c9' colwidth="1*"/>
<thead>
<row>
<entry>Inheritance strategy
<entry>Polymorphic many-to-one
<entry>Polymorphic one-to-one
<entry>Polymorphic one-to-many
<entry>Polymorphic many-to-many
<entry>Polymorphic load()/get()
<entry>Polymorphic queries
<entry>Polymorphic joins
<entry>Outer join fetching
</row>
</thead>
<tbody>
<row>
<entry>table per class-hierarchy
<entry><many-to-one>
<entry><one-to-one>
<entry><one-to-many>
<entry><many-to-many>
<entry>s.get(Payment.class, id)
<entry>from Payment p
<entry>from Order o join o.payment p
<entry>supported
</row>
<row>
<entry>table per subclass
<entry><many-to-one>
<entry><one-to-one>
<entry><one-to-many>
<entry><many-to-many>
<entry>s.get(Payment.class, id)
<entry>from Payment p
<entry>from Order o join o.payment p
<entry>supported
</row>
<row>
<entry>table per concrete-class (union-subclass)
<entry><many-to-one>
<entry><one-to-one>
<entry><one-to-many> (for inverse="true" only)
<entry><many-to-many>
<entry>s.get(Payment.class, id)
<entry>from Payment p
<entry>from Order o join o.payment p
<entry>supported
</row>
<row>
<entry>table per concrete class (implicit polymorphism)
<entry><any>
<entry>not supported
<entry>not supported
<entry><many-to-any>
<entry>s.createCriteria(Payment.class).add( Restrictions.idEq(id) ).uniqueResult()
<entry>from Payment p
<entry>not supported
<entry>not supported
</row>
</tbody>
</tgroup>
</table>
</section>
</chapter>
Other Hibernate examples (source code examples)
Here is a short list of links related to this Hibernate inheritance_mapping.xml source code file:
|