15.8. Inheritance
Prev | Chapter 15. Mapping Metadata | Next

## 15.8. Inheritance

In the 1990's programmers coined the term impedance mismatch to describe the difficulties in bridging the object and relational worlds. Perhaps no feature of object modeling highlights the impedance mismatch better than inheritance. There is no natural, efficient way to represent an inheritance relationship in a relational database.

Luckily, JDOR provides very flexible object-relational mapping of inheritance trees, making the best of a bad situation. Each class in an inheritance hierarchy can use the `inheritance` element to describe its inheritance mapping. This element has a single attribute: `strategy`. In the list that follows, we examine JDOR's standard inheritance strategies. Some vendors may define additional proprietary strategies.

| Note
Kodo does not define any non-standard inheritance models, but does allow you to create your own custom mappings. See the Reference Guide's Section 7.10, “Custom Mappings” for details on writing custom inheritance strategies and pluggin them in to Kodo.

### 15.8.1. subclass-table

The `subclass-table` inheritance strategy indicates that the current class is not mapped to any table at all, and that all of its fields must be mapped by subclasses into their own tables. This strategy is typically used with abstract base classes that are not represented in the relational schema. Classes that declare an inheritance strategy of `subclass-table` should not define the `class` element's `table` attribute, nor should they attempt to define mappings for any fields.

In our model, the abstract `Contract` class uses the `subclass-table` inheritance strategy. `Contract`'s two direct subclasses, `Subscription` and `LineItem`, each map all of `Contract`'s fields into their own tables.

Example 15.4. subclass-table Mapping

    <class name="Contract">
        <inheritance strategy="subclass-table"/>
        ...
    </class>

| Note
The pattern of mapping the fields of an abstract, unmapped base class into the tables of each subclass is often referred to as a horizontal or distributed inheritance mapping.

#### 15.8.1.1. Advantages

An advantage of using the `subclass-table` strategy for abstract base classes is that properties common to multiple persistent subclasses can be defined in the superclass without having to suffer the performance consequences and relational design restrictions inherent in other strategies (which we will examine shortly). Persisting and modifying instances of subclasses is efficient, typically only requiring a single `INSERT` or `UPDATE` statement. Loading relations to these subclasses is also efficient.

#### 15.8.1.2. Disadvantages

Though relations to mapped subclasses of a `subclass-table` class are very efficient, relations to the unmapped base class itself are equally inefficient. When the concrete subclass is not known, the related object could be in any of the subclass tables, making joins through the relation impossible. Subclasses can even use repeated primary key values, forcing the JDOR implementation to record more than just the related primary key values in the database.

This ambiguity also affects queries and identity lookups: queries against a `subclass-table` base class require either multiple `SELECT` statements (one for each mapped subclass), or a complex SQL `UNION`.

| Note
Kodo provides metadata extensions you can use to indicate that a field declared as a relation to a base class is actually a relation to a specific subclass. These extensions often alleviate the need for mapping a relation to a `subclass-table` type. See Section 6.4, “Metadata Extensions”. When a relation to a `subclass-table` class cannot be avoided, Kodo stores either the related object's primary key values or its stringified object id. If the type uses datastore identity or has a concrete application identity class, Kodo stores the primary key values. If the type uses application identity and has an abstract identity class, Kodo must resort to storing the stringified identity object.

#### 15.8.1.3. Additional Considerations

Here are some additional caveats to consider when using the `subclass-table` inheritance mapping:

- Declaring classes abstract. You are not required to make all `subclass-table` classes abstract. However, we recommend that you do so, as any attempt to persist a `subclass-table` base class instance will result in an exception on flush.

- Application identity. When a `subclass-table` superclass uses application identity, you must observe one of the following two restrictions:

  1. The primary key values in each of the tables that extend the `subclass-table` superclass must be unique. In our model, that means that there can be no row in `CNTRCT.SUB` with the same primary key value as a row in `CNTRCT.LINE_ITEM`. This is because a call to `getObjectById` with an application identity instance cannot identify which subclass the ID is associated with.

  2. Rather than having a single application identity class associated with the entire class hierarchy, each subclass declares its own application identity class. The inheritance hierarchy of the application identity classes must exactly match the inheritance hierarchy of the persistent classes they represent, as discussed in Section 4.5.2.1, “Application Identity Hierarchies”.

### 15.8.2. new-table

The `new-table` inheritance strategy employs a new table to hold the fields of the class. You must specify the table name in the `class` element's `table` attribute.

`new-table` is the default strategy for base persistent classes and for subclasses of `subclass-table` classes. Classes that extend non-`subclass-table` base classes can also use this strategy to map their fields to a new table, rather than to the superclass table. The subclass table might contain only subclass state, or might re-map all superclass state as well.

#### 15.8.2.1. Joined

When the subclass table only contains subclass state, the JDOR implementation must be able to link corresponding records in the superclass and subclass tables together to retrieve all of the persistent state for a subclass instance. You tell the JDOR implementation how to do this by nesting a `join` element in your `inheritance` element. Thus, this is often referred to as a joined inheritance strategy.

As its name implies, the `join` element maps a logical foreign key from the subclass table to the superclass table. It has a `column` attribute and nested `column` elements for representing the subclass table's foreign key columns. Section 15.7, “Joins” demonstrated how to use `column`s to map joins. Typically, the subclass table's foreign key columns are also that table's primary key columns.

| Note
Using joined subclass tables is also called vertical inheritance mapping.

All of the classes in our model except `Contract` and `LifetimeSubscription` (not pictured) use the `new-table` strategy. Most of these classes are either base classes or direct subclasses of `Contract`, a `subclass-table` class. In these cases, the `new-table` strategy is the default. `TrialSubscription`, however, extends `Subscription`, which is itself mapped to a table. Therefore, `TrialSubscription` could have mapped its fields to `Subscription`'s table.

Instead, `TrialSubscription` maps its declared fields to the `CNTRCT.TRIAL_SUB` table, and joins to the `CNTRCT.SUB` table for base class state. The join is made by linking the `CNTRCT.TRIAL_SUB.ID` foreign key column to the `CNTRCT.SUB.ID` primary key column. The example below shows how to represent this in mapping metadata.

Example 15.5. Joined Subclass Tables

    <class name="TrialSubscription" table="CNTRCT.TRIAL_SUB">
        <inheritance strategy="new-table">
           <join>
               <column name="ID" target="CNTRCT.SUB.ID"/>
           </join>
        </inheritance>
        ...
    </class>

That is the long version, however. JDOR is smart enough to default the target table to the superclass table, and we can apply join shortcuts to yield a much more concise representation:

    <class name="TrialSubscription" table="CNTRCT.TRIAL_SUB">
        <inheritance strategy="new-table">
           <join column="ID"/>
        </inheritance>
        ...
    </class>

##### 15.8.2.1.1. Advantages

If you want to map a class to a table and none of the superclasses of that class are themselves mapped to a table (or the class has no persistent superclasses), then the `new-table` strategy is your only choice. It is only meaningful to discuss the advantages and disadvantages of the `new-table` strategy for classes that have a superclass mapped to a different table. For example, our model's `TrialSubscription` class extends `Subscription`, yet maps its declared fields to a different table. We could have mapped `TrialSubscription`'s fields to `Subscription`'s table; what made us choose to to use a separate joined table instead?

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 the `new-table` strategy can be loaded through standard joins and can use standard foreign keys, as opposed to the machinations required to load relations to `subclass-table` base types.

##### 15.8.2.1.2. Disadvantages

Using multiple joined tables slows things down. 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.

| Note
When executing a select against a hierarchy that uses joined subclass table inheritance, you must consider how to load subclass state. Section 5.7, “Eager Fetching” in the Reference Guide describes Kodo's options for efficient data loading.

#### 15.8.2.2. Table Per Class

Like the joined `new-table` strategy, the table-per-class `new-table` strategy maps a subclass to its own table. Unlike the joined strategy, however, the subclass table includes all state for an instance of the corresponding class. Thus to load a subclass instance, the JDOR implementation must only read from the subclass table; it does not need to join to superclass tables.

Suppose that our sample model's `Magazine` class has a subclass `Tabloid`. The classes are mapped using the table-per-class strategy, as in the diagram above. In a table-per-class mapping, `Magazine`'s table `MAG` contains all state declared in the base `Magazine` class. `Tabloid` maps to a separate table, `TABLOID`. This table contains not only the state declared in the `Tabloid` subclass, but all the base class state from `Magazine` as well. Thus the `TABLOID` table would contain columns for `isbn`, `title`, and other `Magazine` fields.

Example 15.6. Table Per Class Mapping

    <class name="Tabloid" table="TABLOID">
        <inheritance strategy="new-table"/>
        <field name="Magazine.isbn" column="ISBN"/>
        <field name="Magazine.title" column="TITLE"/>
        ...
        <field name="data" column="TAB_DATA"/>
    </class>

Notice that only the lack of a `join` within the `inheritance` element differentiates a table-per-class strategy from a joined strategy. Also, notice that a table-per-class subclass explicitly re-maps all of its inherited fields into its own table.

##### 15.8.2.2.1. Advantages

The table-per-class strategy is very efficient when operating on instances of a known class. Under these conditions, the strategy never requires joining to superclass or subclass tables. Reads, joins, inserts, updates, and deletes are all efficient in the absence of polymorphic behavior. Also, as in the joined strategy, adding additional classes to the hierarchy does not require modifying existing class tables.

##### 15.8.2.2.2. Disadvantages

Polymorphic relations to a non-leaf classes in a table-per-class hierarchy have many limitations. In some ways, they are similar to relations to a `subclass-table` base class. When the concrete subclass is not known, the related object could be in any of the subclass tables, making joins through the relation impossible. This ambiguity also affects identity lookups and queries; these operations require multiple SQL `SELECT`s (one for each possible subclass), or a complex `UNION`.

| Note
Section 7.8.1, “Table Per Class” in the Reference Guide describes the limitations Kodo places on table-per-class mapping.

### 15.8.3. superclass-table

`superclass-table` is the default strategy for subclasses of `new-table` and other `superclass-table` classes. In this strategy, the subclass' fields are mapped to superclass' table. Classes that use the `superclass-table` inheritance strategy should not specify the `class` element's `table` attribute.

In our model, `Subscription` is mapped to the `CNTRCT.SUB` table. `LifetimeSubscription`, which extends `Subscription`, adds its field data to this table as well.

Example 15.7. superclass-table Mapping

    <class name="LifetimeSubscription">
        <inheritance strategy="superclass-table"/>
        ...
    </class>

| Note
Mapping subclass state to the superclass table is often called flat inheritance mapping.

#### 15.8.3.1. Advantages

`superclass-table` inheritance mapping is the fastest of all inheritance models, since it never requires a join to retrieve a persistent instance from the database. Similarly, persisting or updating a persistent instance requires only a single `INSERT` or `UPDATE` statement. Finally, relations to any class within a `superclass-table` inheritance hierarchy are just as efficient as relations to a base class.

#### 15.8.3.2. Disadvantages

The larger the inheritance model gets, the "wider" the mapped table gets, in that for every field in the entire inheritance hierarchy, a column must exist in the mapped table. This may have undesirable consequence on the database size, since a wide or deep inheritance hierarchy will result in tables with many mostly-empty columns.

### 15.8.4. Putting it All Together

Now that we have covered JDOR's inheritance strategies, we can update our mapping document with inheritance information. Here is the complete model:

And here is the corresponding mapping metadata:

Example 15.8. Inheritance Mapping

    <?xml version="1.0"?>
    <orm>
        <package name="org.mag">
            <sequence name="ArticleSeq" datastore-sequence="ART_SEQ"/>
            <class name="Magazine" table="MAG">
                <!-- not strictly necessary, since this is the default -->
                <inheritance strategy="new-table"/>
                <field name="isbn">
                    <column name="ISBN" jdbc-type="char" length="15"/>
                </field>
                <field name="title" column="TITLE"/>
                ...
            </class>
            <class name="Article" table="ART">
                <!-- not strictly necessary, since this is the default -->
                <inheritance strategy="new-table"/>
                <field name="id" column="ID"/>
                ...
            </class>
        </package>
        <package name="org.mag.pub">
            <sequence name="AuthorSeq" factory-class="Author$SequenceFactory"/>
            <class name="Company" table="COMP">
                <datastore-identity column="CID" strategy="autoassign"/>
                <!-- not strictly necessary, since this is the default -->
                <inheritance strategy="new-table"/>
                ...
            </class>
            <class name="Author" table="AUTH">
                <datastore-identity sequence="AuthorSeq">
                    <column name="AID" sql-type="INTEGER64"/>
                </datastore-identity>
                <!-- not strictly necessary, since this is the default -->
                <inheritance strategy="new-table"/>
                ...
            </class>
        </package>
        <package name="org.mag.subscribe">
            <sequence name="ContractSeq" strategy="transactional"/>
            <class name="Contract">
                <inheritance strategy="subclass-table"/>
                ...
            </class>
            <class name="Subscription" table="CNTRCT.SUB">
                <!-- not strictly necessary, since this is the default -->
                <inheritance strategy="new-table"/>
                <field name="Contract.id" column="ID"/>
                ...
            </class>
            <class name="LifetimeSubscription">
                <!-- not strictly necessary, since this is the default -->
                <inheritance strategy="superclass-table"/>
                ...
            </class>
            <class name="TrialSubscription" table="CNTRCT.TRIAL_SUB">
                <inheritance strategy="new-table">
                    <join column="ID"/>
                </inheritance>
                ...
            </class>
            <class name="Subscription$LineItem" table="CNTRCT.LINE_ITEM">
                <!-- not strictly necessary, since this is the default -->
                <inheritance strategy="new-table"/>
                <field name="Contract.id" column="ID"/>
                ...
            </class>
        </package>
    </orm>

Prev | Up | Next
15.7. Joins | Home | 15.9. Discriminator