revised inheritance and components, minor fixes to example
git-svn-id: https://svn.jboss.org/repos/hibernate/trunk/Hibernate3/doc@5573 1b8cb986-b30d-0410-93ca-fae66ebed9b2
This commit is contained in:
parent
0b8ee71d7f
commit
35cf78f98a
|
@ -236,7 +236,7 @@
|
||||||
<title>Components as Map indices</title>
|
<title>Components as Map indices</title>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
The <literal><composite-index></literal> element lets you map a
|
The <literal><composite-map-key></literal> element lets you map a
|
||||||
component class as the key of a <literal>Map</literal>. Make sure you override
|
component class as the key of a <literal>Map</literal>. Make sure you override
|
||||||
<literal>hashCode()</literal> and <literal>equals()</literal> correctly on
|
<literal>hashCode()</literal> and <literal>equals()</literal> correctly on
|
||||||
the component class.
|
the component class.
|
||||||
|
@ -266,92 +266,110 @@
|
||||||
</listitem>
|
</listitem>
|
||||||
</itemizedlist>
|
</itemizedlist>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
<emphasis>Note: in Hibernate3, the second requirement is not an absolutely hard
|
||||||
|
requirement of Hibernate. But do it anyway.</emphasis>
|
||||||
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
You can't use an <literal>IdentifierGenerator</literal> to generate composite keys.
|
You can't use an <literal>IdentifierGenerator</literal> to generate composite keys.
|
||||||
Instead the application must assign its own identifiers.
|
Instead the application must assign its own identifiers.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
|
||||||
Since a composite identifier must be assigned to the object before saving it,
|
|
||||||
we can't use <literal>unsaved-value</literal> of the identifier to distinguish
|
|
||||||
between newly instantiated transient instances and detached instances from a
|
|
||||||
previous session.
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
TODO: document new auto-detect features for assigned IDs in H3
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
So, if you wish to use transitive reattachment (you don't have to), you must
|
|
||||||
either implement <literal>Interceptor.isUnsaved()</literal> or define the
|
|
||||||
<literal>unsaved-value</literal> of a <literal><version></literal> or
|
|
||||||
<literal><timestamp></literal> element.
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
Use the <literal><composite-id></literal> tag (with nested
|
Use the <literal><composite-id></literal> tag (with nested
|
||||||
<literal><key-property></literal> elements) in place of the
|
<literal><key-property></literal> elements) in place of the usual
|
||||||
usual <literal><id></literal> declaration:
|
<literal><id></literal> declaration. For example, the
|
||||||
|
<literal>OrderLine</literal> class has a primary key that depends upon
|
||||||
|
the (composite) primary key of <literal>Order</literal>.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<programlisting><![CDATA[<class name="eg.Foo" table"FOOS">
|
<programlisting><![CDATA[<class name="OrderLine">
|
||||||
<composite-id name="compId" class="eg.FooCompositeID">
|
|
||||||
<key-property name="string"/>
|
<composite-id name="id" class="OrderLineId">
|
||||||
<key-property name="short"/>
|
<key-property name="lineId"/>
|
||||||
<key-property name="date" column="date_" type="date"/>
|
<key-property name="orderId"/>
|
||||||
|
<key-property name="customerId"/>
|
||||||
</composite-id>
|
</composite-id>
|
||||||
|
|
||||||
<property name="name"/>
|
<property name="name"/>
|
||||||
|
|
||||||
|
<many-to-one name="order" class="Order"
|
||||||
|
insert="false" update="false">
|
||||||
|
<column name="orderId"/>
|
||||||
|
<column name="customerId"/>
|
||||||
|
</many-to-one>
|
||||||
....
|
....
|
||||||
|
|
||||||
</class>]]></programlisting>
|
</class>]]></programlisting>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
Now, any foreign keys into the table <literal>FOOS</literal> are also composite.
|
Now, any foreign keys referencing the <literal>OrderLine</literal> table are also
|
||||||
You must declare this in your mappings for other classes. An association to
|
composite. You must declare this in your mappings for other classes. An association
|
||||||
<literal>Foo</literal> would be declared like this:
|
to <literal>OrderLine</literal> would be mapped like this:
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<programlisting><![CDATA[<many-to-one name="foo" class="eg.Foo">
|
<programlisting><![CDATA[<many-to-one name="orderLine" class="OrderLine">
|
||||||
<!-- the "class" attribute is optional, as usual -->
|
<!-- the "class" attribute is optional, as usual -->
|
||||||
<column name="foo_string"/>
|
<column name="lineId"/>
|
||||||
<column name="foo_short"/>
|
<column name="orderId"/>
|
||||||
<column name="foo_date"/>
|
<column name="customerId"/>
|
||||||
</many-to-one>]]></programlisting>
|
</many-to-one>]]></programlisting>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
This new <literal><column></literal> tag is also used by multi-column custom types.
|
(Note that the <literal><column></literal> tag is an alternative to the
|
||||||
Actually it is an alternative to the <literal>column</literal> attribute everywhere. A
|
<literal>column</literal> attribute everywhere.)
|
||||||
collection with elements of type <literal>Foo</literal> would use:
|
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<programlisting><![CDATA[<set name="foos">
|
<para>
|
||||||
<key column="owner_id"/>
|
A <literal>many-to-many</literal> association to <literal>OrderLine</literal> also
|
||||||
<many-to-many class="eg.Foo">
|
uses the composite foreign key:
|
||||||
<column name="foo_string"/>
|
</para>
|
||||||
<column name="foo_short"/>
|
|
||||||
<column name="foo_date"/>
|
<programlisting><![CDATA[<set name="undeliveredOrderLines">
|
||||||
|
<key column name="warehouseId"/>
|
||||||
|
<many-to-many class="OrderLine">
|
||||||
|
<column name="lineId"/>
|
||||||
|
<column name="orderId"/>
|
||||||
|
<column name="customerId"/>
|
||||||
</many-to-many>
|
</many-to-many>
|
||||||
</set>]]></programlisting>
|
</set>]]></programlisting>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
On the other hand, <literal><one-to-many></literal>, as usual, declares no columns.
|
The collection of <literal>OrderLine</literal>s in <literal>Order</literal> would
|
||||||
|
use:
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<programlisting><![CDATA[<set name="orderLines" inverse="true">
|
||||||
|
<key>
|
||||||
|
<column name="orderId"/>
|
||||||
|
<column name="customerId"/>
|
||||||
|
</key>
|
||||||
|
<one-to-many class="OrderLine"/>
|
||||||
|
</set>]]></programlisting>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
(The <literal><one-to-many></literal> element, as usual, declares no columns.)
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
If <literal>Foo</literal> itself contains collections, they will also need a
|
If <literal>OrderLine</literal> itself owns a collection, it also has a composite
|
||||||
composite foreign key.
|
foreign key.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<programlisting><![CDATA[<class name="eg.Foo">
|
<programlisting><![CDATA[<class name="OrderLine">
|
||||||
....
|
....
|
||||||
....
|
....
|
||||||
<set name="dates" lazy="true">
|
<list name="deliveryAttempts">
|
||||||
<key> <!-- a collection inherits the composite key type -->
|
<key> <!-- a collection inherits the composite key type -->
|
||||||
<column name="foo_string"/>
|
<column name="lineId"/>
|
||||||
<column name="foo_short"/>
|
<column name="orderId"/>
|
||||||
<column name="foo_date"/>
|
<column name="customerId"/>
|
||||||
</key>
|
</key>
|
||||||
<element column="foo_date" type="date"/>
|
<list-index column="attemptId" base="1"/>
|
||||||
|
<composite-element class="DeliveryAttempt">
|
||||||
|
...
|
||||||
|
</composite-element>
|
||||||
</set>
|
</set>
|
||||||
</class>]]></programlisting>
|
</class>]]></programlisting>
|
||||||
|
|
||||||
|
@ -367,7 +385,7 @@
|
||||||
<programlisting><![CDATA[<dynamic-component name="userAttributes">
|
<programlisting><![CDATA[<dynamic-component name="userAttributes">
|
||||||
<property name="foo" column="FOO"/>
|
<property name="foo" column="FOO"/>
|
||||||
<property name="bar" column="BAR"/>
|
<property name="bar" column="BAR"/>
|
||||||
<many-to-one name="baz" class="eg.Baz" column="BAZ"/>
|
<many-to-one name="baz" class="Baz" column="BAZ_ID"/>
|
||||||
</dynamic-component>]]></programlisting>
|
</dynamic-component>]]></programlisting>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
|
|
|
@ -154,12 +154,8 @@ create sequence employer_id_seq]]></programlisting>
|
||||||
|
|
||||||
<property name="title"/>
|
<property name="title"/>
|
||||||
<set name="authors" table="author_work">
|
<set name="authors" table="author_work">
|
||||||
<key>
|
<key column name="work_id"/>
|
||||||
<column name="work_id" not-null="true"/>
|
<many-to-many class="Author" column name="author_id"/>
|
||||||
</key>
|
|
||||||
<many-to-many class="Author">
|
|
||||||
<column name="author_id" not-null="true"/>
|
|
||||||
</many-to-many>
|
|
||||||
</set>
|
</set>
|
||||||
|
|
||||||
<subclass name="Book" discriminator-value="B">
|
<subclass name="Book" discriminator-value="B">
|
||||||
|
@ -292,7 +288,7 @@ alter table author_work
|
||||||
<many-to-one name="customer" column="customer_id"/>
|
<many-to-one name="customer" column="customer_id"/>
|
||||||
<list name="lineItems" table="line_items">
|
<list name="lineItems" table="line_items">
|
||||||
<key column="order_id"/>
|
<key column="order_id"/>
|
||||||
<index column="line_number"/>
|
<list-index column="line_number"/>
|
||||||
<composite-element class="LineItem">
|
<composite-element class="LineItem">
|
||||||
<property name="quantity"/>
|
<property name="quantity"/>
|
||||||
<many-to-one name="product" column="product_id"/>
|
<many-to-one name="product" column="product_id"/>
|
||||||
|
|
|
@ -5,12 +5,7 @@
|
||||||
<title>The Three Strategies</title>
|
<title>The Three Strategies</title>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
TODO: While this is all still supported, many new features would require
|
Hibernate supports the three basic inheritance mapping strategies:
|
||||||
a rewrite of this whole chapter
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
Hibernate supports the three basic inheritance mapping strategies.
|
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<itemizedlist>
|
<itemizedlist>
|
||||||
|
@ -26,25 +21,45 @@
|
||||||
</listitem>
|
</listitem>
|
||||||
<listitem>
|
<listitem>
|
||||||
<para>
|
<para>
|
||||||
table per concrete class (some limitations)
|
table per concrete class
|
||||||
</para>
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
</itemizedlist>
|
</itemizedlist>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
It is even possible to use different mapping strategies for different
|
In addition, Hibernate supports a fourth, slightly different kind of
|
||||||
branches of the same inheritance hierarchy, but the same limitations
|
polymorphism:
|
||||||
apply as apply to table-per-concrete class mappings. Hibernate does
|
|
||||||
not support mixing <literal><subclass></literal> mappings and
|
|
||||||
<literal><joined-subclass></literal> mappings inside the same
|
|
||||||
<literal><class></literal> element. However, it is possible to
|
|
||||||
use a <literal><join></literal> element to map this.
|
|
||||||
</para>
|
</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, and then make use of implicit
|
||||||
|
polymorphism to achieve polymorphism across the whole hierarchy. However,
|
||||||
|
Hibernate does not support mixing <literal><subclass></literal>,
|
||||||
|
and <literal><joined-subclass></literal> and
|
||||||
|
<literal><union-subclass></literal> mappings under the same root
|
||||||
|
<literal><class></literal> element. It is possible to mix together
|
||||||
|
the table per hierarchy and table per subclass strategies, under the
|
||||||
|
the same <literal><class></literal> element, by combining the
|
||||||
|
<literal><subclass></literal> and <literal><join></literal>
|
||||||
|
elements (see below).
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<sect2>
|
||||||
|
<title>Table per class hierarchy</title>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
Suppose we have an interface <literal>Payment</literal>, with implementors
|
Suppose we have an interface <literal>Payment</literal>, with implementors
|
||||||
<literal>CreditCardPayment</literal>, <literal>CashPayment</literal>,
|
<literal>CreditCardPayment</literal>, <literal>CashPayment</literal>,
|
||||||
<literal>ChequePayment</literal>. The table-per-hierarchy mapping would
|
<literal>ChequePayment</literal>. The table per hierarchy mapping would
|
||||||
look like:
|
look like:
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
|
@ -56,6 +71,7 @@
|
||||||
<property name="amount" column="AMOUNT"/>
|
<property name="amount" column="AMOUNT"/>
|
||||||
...
|
...
|
||||||
<subclass name="CreditCardPayment" discriminator-value="CREDIT">
|
<subclass name="CreditCardPayment" discriminator-value="CREDIT">
|
||||||
|
<property name="creditCardType" column="CCTYPE"/>
|
||||||
...
|
...
|
||||||
</subclass>
|
</subclass>
|
||||||
<subclass name="CashPayment" discriminator-value="CASH">
|
<subclass name="CashPayment" discriminator-value="CASH">
|
||||||
|
@ -67,13 +83,18 @@
|
||||||
</class>]]></programlisting>
|
</class>]]></programlisting>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
Exactly one table is required. There is one big limitation of this
|
Exactly one table is required. There is one big limitation of this mapping
|
||||||
mapping strategy: columns declared by the subclasses may not have
|
strategy: columns declared by the subclasses, such as <literal>CCTYPE</literal>,
|
||||||
<literal>NOT NULL</literal> constraints.
|
may not have <literal>NOT NULL</literal> constraints.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
|
</sect2>
|
||||||
|
|
||||||
|
<sect2>
|
||||||
|
<title>Table per class subclass</title>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
A table-per-subclass mapping would look like:
|
A table per subclass mapping would look like:
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<programlisting><![CDATA[<class name="Payment" table="PAYMENT">
|
<programlisting><![CDATA[<class name="Payment" table="PAYMENT">
|
||||||
|
@ -84,6 +105,7 @@
|
||||||
...
|
...
|
||||||
<joined-subclass name="CreditCardPayment" table="CREDIT_PAYMENT">
|
<joined-subclass name="CreditCardPayment" table="CREDIT_PAYMENT">
|
||||||
<key column="PAYMENT_ID"/>
|
<key column="PAYMENT_ID"/>
|
||||||
|
<property name="creditCardType" column="CCTYPE"/>
|
||||||
...
|
...
|
||||||
</joined-subclass>
|
</joined-subclass>
|
||||||
<joined-subclass name="CashPayment" table="CASH_PAYMENT">
|
<joined-subclass name="CashPayment" table="CASH_PAYMENT">
|
||||||
|
@ -102,34 +124,140 @@
|
||||||
is actually a one-to-one association).
|
is actually a one-to-one association).
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
|
</sect2>
|
||||||
|
|
||||||
|
<sect2>
|
||||||
|
<title>Table per subclass, using a discriminator</title>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
Note that Hibernate's implementation of table-per-subclass requires
|
Note that Hibernate's implementation of table per subclass requires
|
||||||
no discriminator column. Other object/relational mappers use a
|
no discriminator column. Other object/relational mappers use a
|
||||||
different implementation of table-per-subclass which requires a type
|
different implementation of table per subclass which requires a type
|
||||||
discriminator column in the superclass table. The approach taken by
|
discriminator column in the superclass table. The approach taken by
|
||||||
Hibernate is much more difficult to implement but arguably more
|
Hibernate is much more difficult to implement but arguably more
|
||||||
correct from a relational point of view.
|
correct from a relational point of view. If you would like to use
|
||||||
|
a discriminator column with the table per subclass strategy, you
|
||||||
|
may combine the use of <literal><subclass></literal> and
|
||||||
|
<literal><join></literal>, as follow:
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<programlisting><![CDATA[<class name="Payment" table="PAYMENT">
|
||||||
TODO: document usage of join for discriminators in table-per-subclass
|
<id name="id" type="long" column="PAYMENT_ID">
|
||||||
</para>
|
<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">
|
||||||
|
<join table="CASH_PAYMENT">
|
||||||
|
...
|
||||||
|
</join>
|
||||||
|
</subclass>
|
||||||
|
<subclass name="ChequePayment" discriminator-value="CHEQUE">
|
||||||
|
<join table="CHEQUE_PAYMENT" fetch="select">
|
||||||
|
...
|
||||||
|
</join>
|
||||||
|
</subclass>
|
||||||
|
</class>]]></programlisting>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
TODO: document usage of join for mixing inheritance mapping strategies
|
The optional <literal>fetch="select"</literal> declaration tells Hibernate
|
||||||
|
not to fetch the <literal>ChequePayment</literal> subclass data using an
|
||||||
|
outer join when querying the superclass.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
|
</sect2>
|
||||||
|
|
||||||
|
<sect2>
|
||||||
|
<title>Mixing table per class hierarchy with table per subclass</title>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
For either of these two mapping strategies, a polymorphic
|
You may even mix the table per hierarchy and table per subclass strategies
|
||||||
association to <literal>Payment</literal> is mapped using
|
using this approach:
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<programlisting><![CDATA[<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>]]></programlisting>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
For any of these mapping strategies, a polymorphic association to the root
|
||||||
|
<literal>Payment</literal> class is mapped using
|
||||||
<literal><many-to-one></literal>.
|
<literal><many-to-one></literal>.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<programlisting><![CDATA[<many-to-one name="payment"
|
<programlisting><![CDATA[<many-to-one name="payment" column="PAYMENT_ID" class="Payment"/>]]></programlisting>
|
||||||
column="PAYMENT"
|
|
||||||
class="Payment"/>]]></programlisting>
|
|
||||||
|
|
||||||
<para>The table-per-concrete-class strategy is very different.</para>
|
</sect2>
|
||||||
|
|
||||||
|
<sect2>
|
||||||
|
<title>Table per concrete class</title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
There are two ways we could go about mapping the table per concrete class
|
||||||
|
strategy. The first is to use <literal><union-subclass></literal>.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<programlisting><![CDATA[<class name="Payment">
|
||||||
|
<id name="id" type="long" column="PAYMENT_ID">
|
||||||
|
<generator class="native"/>
|
||||||
|
</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>]]></programlisting>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Three tables are involved. 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.
|
||||||
|
(We might relax this in a future release of Hibernate.)
|
||||||
|
</para>
|
||||||
|
|
||||||
|
</sect2>
|
||||||
|
|
||||||
|
<sect2>
|
||||||
|
<title>Table per concrete class, using implicit polymorphism</title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
An alternative approach is to make use of implicit polymorphism:
|
||||||
|
</para>
|
||||||
|
|
||||||
<programlisting><![CDATA[<class name="CreditCardPayment" table="CREDIT_PAYMENT">
|
<programlisting><![CDATA[<class name="CreditCardPayment" table="CREDIT_PAYMENT">
|
||||||
<id name="id" type="long" column="CREDIT_PAYMENT_ID">
|
<id name="id" type="long" column="CREDIT_PAYMENT_ID">
|
||||||
|
@ -156,48 +284,40 @@
|
||||||
</class>]]></programlisting>
|
</class>]]></programlisting>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
Three tables were required. Notice that nowhere do we
|
Notice that nowhere do we mention the <literal>Payment</literal> interface
|
||||||
mention the <literal>Payment</literal> interface explicitly.
|
explicitly. Also notice that properties of <literal>Payment</literal> are
|
||||||
Instead, we make use of Hibernate's <emphasis>implicit
|
mapped in each of the subclasses.
|
||||||
polymorphism</emphasis>. Also notice that properties of
|
|
||||||
<literal>Payment</literal> are mapped in each of the
|
|
||||||
subclasses.
|
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
In this case, a polymorphic association to <literal>Payment</literal>
|
The disadvantage of this approach is that Hibernate does not generate SQL
|
||||||
is mapped using <literal><any></literal>.
|
<literal>UNION</literal>s when performing polymorphic queries.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<programlisting><![CDATA[<any name="payment"
|
<para>
|
||||||
meta-type="class"
|
For this mapping strategy, a polymorphic association to <literal>Payment</literal>
|
||||||
id-type="long">
|
is usually mapped using <literal><any></literal>.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<programlisting><![CDATA[<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_CLASS"/>
|
||||||
<column name="PAYMENT_ID"/>
|
<column name="PAYMENT_ID"/>
|
||||||
</any>]]></programlisting>
|
</any>]]></programlisting>
|
||||||
|
|
||||||
<para>
|
</sect2>
|
||||||
It would be better if we defined a <literal>UserType</literal>
|
|
||||||
as the <literal>meta-type</literal>, to handle the mapping from
|
|
||||||
type discriminator strings to <literal>Payment</literal> subclass.
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<programlisting><![CDATA[<any name="payment"
|
<sect2>
|
||||||
meta-type="PaymentMetaType"
|
<title>Mixing implicit polymorphism with other inheritance mappings</title>
|
||||||
id-type="long">
|
|
||||||
<column name="PAYMENT_TYPE"/> <!-- CREDIT, CASH or CHEQUE -->
|
|
||||||
<column name="PAYMENT_ID"/>
|
|
||||||
</any>]]></programlisting>
|
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
There is one further thing to notice about this mapping.
|
There is one further thing to notice about this mapping. Since the subclasses
|
||||||
Since the subclasses are each mapped in their own
|
are each mapped in their own <literal><class></literal> element (and since
|
||||||
<literal><class></literal> element (and since
|
<literal>Payment</literal> is just an interface), each of the subclasses could
|
||||||
<literal>Payment</literal> is just an interface), each of
|
easily be part of another inheritance hierarchy! (And you can still use polymorphic
|
||||||
the subclasses could easily be part of another table-per-class
|
queries against the <literal>Payment</literal> interface.)
|
||||||
or table-per-subclass inheritance hierarchy! (And you can
|
|
||||||
still use polymorphic queries against the
|
|
||||||
<literal>Payment</literal> interface.)
|
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<programlisting><![CDATA[<class name="CreditCardPayment" table="CREDIT_PAYMENT">
|
<programlisting><![CDATA[<class name="CreditCardPayment" table="CREDIT_PAYMENT">
|
||||||
|
@ -238,9 +358,7 @@
|
||||||
not instances of <literal>NonelectronicTransaction</literal>.
|
not instances of <literal>NonelectronicTransaction</literal>.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
</sect2>
|
||||||
TODO: Document union-subclass for polymorphic-table-per-concrete-class mappings
|
|
||||||
</para>
|
|
||||||
|
|
||||||
</sect1>
|
</sect1>
|
||||||
|
|
||||||
|
@ -249,13 +367,13 @@
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
There are certain limitations to the "implicit polymorphism" approach to
|
There are certain limitations to the "implicit polymorphism" approach to
|
||||||
the table-per-concrete-class mapping strategy. There are somewhat less
|
the table per concrete-class mapping strategy. There are somewhat less
|
||||||
restrictive limitations to <literal><union-subclass></literal>
|
restrictive limitations to <literal><union-subclass></literal>
|
||||||
mappings. (TODO)
|
mappings.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
The following table shows the limitations of table-per-concrete-class
|
The following table shows the limitations of table per concrete-class
|
||||||
mappings, and of implicit polymorphism, in Hibernate.
|
mappings, and of implicit polymorphism, in Hibernate.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
|
@ -285,7 +403,7 @@
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<row>
|
<row>
|
||||||
<entry>table-per-class-hierarchy</entry>
|
<entry>table per class-hierarchy</entry>
|
||||||
<entry><literal><many-to-one></literal></entry>
|
<entry><literal><many-to-one></literal></entry>
|
||||||
<entry><literal><one-to-one></literal></entry>
|
<entry><literal><one-to-one></literal></entry>
|
||||||
<entry><literal><one-to-many></literal></entry>
|
<entry><literal><one-to-many></literal></entry>
|
||||||
|
@ -296,7 +414,7 @@
|
||||||
<entry><emphasis>supported</emphasis></entry>
|
<entry><emphasis>supported</emphasis></entry>
|
||||||
</row>
|
</row>
|
||||||
<row>
|
<row>
|
||||||
<entry>table-per-subclass</entry>
|
<entry>table per subclass</entry>
|
||||||
<entry><literal><many-to-one></literal></entry>
|
<entry><literal><many-to-one></literal></entry>
|
||||||
<entry><literal><one-to-one></literal></entry>
|
<entry><literal><one-to-one></literal></entry>
|
||||||
<entry><literal><one-to-many></literal></entry>
|
<entry><literal><one-to-many></literal></entry>
|
||||||
|
@ -307,18 +425,7 @@
|
||||||
<entry><emphasis>supported</emphasis></entry>
|
<entry><emphasis>supported</emphasis></entry>
|
||||||
</row>
|
</row>
|
||||||
<row>
|
<row>
|
||||||
<entry>table-per-concrete-class (implicit polymorphism)</entry>
|
<entry>table per concrete-class (union-subclass)</entry>
|
||||||
<entry><literal><any></literal></entry>
|
|
||||||
<entry><emphasis>not supported</emphasis></entry>
|
|
||||||
<entry><emphasis>not supported</emphasis></entry>
|
|
||||||
<entry><literal><many-to-any></literal></entry>
|
|
||||||
<entry><emphasis>use a query</emphasis></entry>
|
|
||||||
<entry><literal>from Payment p</literal></entry>
|
|
||||||
<entry><emphasis>not supported</emphasis></entry>
|
|
||||||
<entry><emphasis>not supported</emphasis></entry>
|
|
||||||
</row>
|
|
||||||
<row>
|
|
||||||
<entry>table-per-concrete-class (union-subclass)</entry>
|
|
||||||
<entry><literal><many-to-one></literal></entry>
|
<entry><literal><many-to-one></literal></entry>
|
||||||
<entry><literal><one-to-one></literal></entry>
|
<entry><literal><one-to-one></literal></entry>
|
||||||
<entry><literal><one-to-many></literal> (for <literal>inverse="true"</literal> only)</entry>
|
<entry><literal><one-to-many></literal> (for <literal>inverse="true"</literal> only)</entry>
|
||||||
|
@ -328,6 +435,17 @@
|
||||||
<entry><literal>from Order o join o.payment p</literal></entry>
|
<entry><literal>from Order o join o.payment p</literal></entry>
|
||||||
<entry><emphasis>supported</emphasis></entry>
|
<entry><emphasis>supported</emphasis></entry>
|
||||||
</row>
|
</row>
|
||||||
|
<row>
|
||||||
|
<entry>table per concrete class (implicit polymorphism)</entry>
|
||||||
|
<entry><literal><any></literal></entry>
|
||||||
|
<entry><emphasis>not supported</emphasis></entry>
|
||||||
|
<entry><emphasis>not supported</emphasis></entry>
|
||||||
|
<entry><literal><many-to-any></literal></entry>
|
||||||
|
<entry><literal>s.createCriteria(Payment.class).add( Restrictions.idEq(id) ).uniqueResult()</literal></entry>
|
||||||
|
<entry><literal>from Payment p</literal></entry>
|
||||||
|
<entry><emphasis>not supported</emphasis></entry>
|
||||||
|
<entry><emphasis>not supported</emphasis></entry>
|
||||||
|
</row>
|
||||||
</tbody>
|
</tbody>
|
||||||
</tgroup>
|
</tgroup>
|
||||||
</table>
|
</table>
|
||||||
|
|
Loading…
Reference in New Issue