Apr 9, 2015

JPA Joined Inheritance

The InheritanceType.JOINED strategy uses a different table for each class in the hierarchy. Each table only includes state declared in its class. Thus to load a subclass instance, the JPA implementation must read from the subclass table as well as the table of each ancestor class, up to the base entity class.

Note

Using joined subclass tables is also called vertical inheritance mapping.
PrimaryKeyJoinColumn annotations tell the JPA implementation how to join each subclass table record to the corresponding record in its direct superclass table. In our model, the LINE_ITEM.ID column joins to the CONTRACT.ID column. The PrimaryKeyJoinColumn annotation has the following properties:
  • String name: The name of the subclass table column. When there is a single identity field, defaults to that field's column name.
  • String referencedColumnName: The name of the superclass table column this subclass table column joins to. When there is a single identity field, defaults to that field's column name.
  • String columnDefinition: This property has the same meaning as the columnDefinition property on the Column annotation, described in Section 3, “ Column ”.
The XML equivalent is the primary-key-join-column element. Its attributes mirror the annotation properties described above:
  • name
  • referenced-column-name
  • column-definition
The example below shows how we use InheritanceTable.JOINED and a primary key join column to map our sample model according to the diagram above. Note that a primary key join column is not strictly needed, because there is only one identity column, and the subclass table column has the same name as the superclass table column. In this situation, the defaults suffice. However, we include the primary key join column for illustrative purposes.

Example 12.6.  Joined Subclass Tables
@Entity
@Table(schema="CNTRCT")
@Inheritance(strategy=InheritanceType.JOINED)
public class Contract
    extends Document {
    ...
}

public class Subscription {
    ...

    @Entity
    @Table(name="LINE_ITEM", schema="CNTRCT")
    @PrimaryKeyJoinColumn(name="ID", referencedColumnName="ID")
    public static class LineItem
        extends Contract {
        ...
    }
}
The same metadata expressed in XML form:
<entity class="org.mag.subcribe.Contract">
    <table schema="CNTRCT"/>
    <inheritance strategy="JOINED"/>
    ...
</entity>
<entity class="org.mag.subscribe.Subscription.LineItem">
    <table name="LINE_ITEM" schema="CNTRCT"/>
    <primary-key-join-column name="ID" referenced-column-name="PK"/>
    ...
</entity>

When there are multiple identity columns, you must define multiple PrimaryKeyJoinColumns using the aptly-named PrimaryKeyJoinColumns annotation. This annotation's value is an array of PrimaryKeyJoinColumn s. We could rewrite LineItem's mapping as:
@Entity
@Table(name="LINE_ITEM", schema="CNTRCT")
@PrimaryKeyJoinColumns({
    @PrimaryKeyJoinColumn(name="ID", referencedColumnName="ID")
})
public static class LineItem
    extends Contract {
    ...
}
In XML, simply list as many primary-key-join-column elements as necessary.

6.2.1.  Advantages

The joined strategy has the following advantages:
  1. Using joined subclass tables results in the most normalized database schema, meaning the schema with the least spurious or redundant data.
  2. As more subclasses are added to the data model over time, the only schema modification that needs to be made is the addition of corresponding subclass tables in the database (rather than having to change the structure of existing tables).
  3. Relations to a base class using this strategy can be loaded through standard joins and can use standard foreign keys, as opposed to the machinations required to load polymorphic relations to table-per-class base types, described below.

6.2.2.  Disadvantages

Aside from certain uses of the table-per-class strategy described below, the joined strategy is often the slowest of the inheritance models. Retrieving any subclass requires one or more database joins, and storing subclasses requires multiple INSERT or UPDATE statements. This is only the case when persistence operations are performed on subclasses; if most operations are performed on the least-derived persistent superclass, then this mapping is very fast.

0 comments:

Post a Comment