Inheritance Mapping
The Three Strategies
Hibernate supports the three basic inheritance mapping strategies.
table per class hierarchy
table per subclass
table per concrete class (some limitations)
It is even possible to use different mapping strategies for different
branches of the same inheritance hierarchy, but the same limitations
apply as apply to table-per-concrete class mappings. Hibernate does
not support mixing <subclass> mappings and
<joined-subclass> mappings inside the same
<class> element. However, it is possible to
use a <join> element to map this.
Suppose we have an interface Payment, with implementors
CreditCardPayment, CashPayment,
ChequePayment. The table-per-hierarchy mapping would
look like:
...
...
...
...
]]>
Exactly one table is required. There is one big limitation of this
mapping strategy: columns declared by the subclasses may not have
NOT NULL constraints.
A table-per-subclass mapping would look like:
...
...
...
...
]]>
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).
Note that Hibernate's implementation of table-per-subclass requires
no discriminator column. Other object/relational mappers use a
different implementation of table-per-subclass which 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.
TODO: document usage of join for discriminators in table-per-subclass
TODO: document usage of join for mixing inheritance mapping strategies
For either of these two mapping strategies, a polymorphic
association to Payment is mapped using
<many-to-one>.
]]>
The table-per-concrete-class strategy is very different.
...
...
...
]]>
Three tables were required. Notice that nowhere do we
mention the Payment interface explicitly.
Instead, we make use of Hibernate's implicit
polymorphism. Also notice that properties of
Payment are mapped in each of the
subclasses.
In this case, a polymorphic association to Payment
is mapped using <any>.
]]>
It would be better if we defined a UserType
as the meta-type, to handle the mapping from
type discriminator strings to Payment subclass.
]]>
There is one further thing to notice about this mapping.
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 table-per-class
or table-per-subclass inheritance hierarchy! (And you can
still use polymorphic queries against the
Payment interface.)
...
...
...
...
]]>
Once again, we don't mention Payment 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.
TODO: Document union-subclass for polymorphic-table-per-concrete-class mappings
Limitations
There are certain limitations to the "implicit polymorphism" approach to
the table-per-concrete-class mapping strategy. There are somewhat less
restrictive limitations to <union-subclass>
mappings. (TODO)
The following table shows the limitations of table-per-concrete-class
mappings, and of implicit polymorphism, in Hibernate.
Features of inheritance mappings
Inheritance strategy
Polymorphic many-to-one
Polymorphic one-to-one
Polymorphic one-to-many
Polymorphic many-to-many
Polymorphic load()/get()
Polymorphic queries
Polymorphic joins
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
table-per-concrete-class (implicit polymorphism)
<any>
not supported
not supported
<many-to-any>
use a query
from Payment p
not supported
not supported
table-per-concrete-class (union-subclass)
<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