5.7 Inheritance

You may have one or more inheritance hierarchies in your object model. JDO implementations provide an assortment of approaches for mapping the Java classes in an inheritance hierarchy into the nonhierarchical relational tables. To understand the different mapping alternatives that are available, consider the inheritance hierarchy in Figure 5-1.

Figure 5-1. Inheritance hierarchy to be mapped to tables

JDO implementations support one or more of the following mapping strategies:

  • Each class in the hierarchy has a separate table. With this approach, a separate table is used for each class: A, B1, B2, C1, C2, C3, C4. Each table contains only the fields from its associated class. To access all the fields of a C1 instance, including the fields inherited from A and B1, it is necessary to access the tables corresponding to A, B1, and C1. Accessing a B2 instance requires accessing A and B2.

    With this approach, typically the primary keys for B1 and B2 are defined as foreign keys on A, the primary keys for C1 and C2 are defined as foreign keys on B1, and the primary keys for C3 and C4 are defined as foreign keys on B2.

  • Each class in the hierarchy has a separate table, but inherited fields are duplicated in the tables for each subclass. This approach avoids the need to access the tables for A and B1 when accessing an instance of C1; only C1 needs to be accessed. However, when you use this mapping strategy, support for inheritance and polymorphism becomes very cumbersome. Accessing an instance of class A requires a join of all of A's tables.

  • The hierarchy is flattened into a single table containing all the classes. This is the default approach used for many JDO implementations. All of the classes in the hierarchy are placed in one table, which must have a column for every field of every class in the hierarchy. Essentially, all of the classes in a hierarchy are merged into one table. This approach relies on the datastore's efficient storage-management support of null fields, since a row for an instance of C2 will not use the fields of C1, B2, C3, and C4.

    With this approach, the JDO implementation uses an additional type-discriminator column that has a unique value for each class stored in the table. When you retrieve the values for an instance, the value of this column determines the class of the instance to be constructed.

  • Combination of separate classes and flattened hierarchy. This approach combines fields from multiple classes into a number of tables, but the mapping between classes and tables is not one to one. For example, suppose you define three tables: A, B1, and B2.

    • Table A contains the primary key, a type-discriminator column, and all the fields declared in class A.

    • Table B1 contains a primary key that is also a foreign key to table A, and columns for each field in classes B1, C1, and C2.

    • Table B2 contains a primary key that is also a foreign key to table A, and columns for each field in classes B2, C3, and C4.

  • Leaves of the hierarchy determine the tables. This approach results in four tables, corresponding to the C1, C2, C3, and C4 classes. But there may also be instances of A, B1, and B2. The classes are grouped, by default, into the following tables:

    • Table 1 contains the data for the A, B1, and C1 classes.

    • Table 2 contains the data for the C2 class.

    • Table 3 contains the data for the B2 and C3 classes.

    • Table 4 contains the data for the C4 class.

A vendor may support one or more of these inheritance-mapping approaches. All of the approaches are vendor-specific; JDO does not standardize inheritance-mapping. Each approach has performance implications, since an instance's field values may be spread among several tables that must be joined and accessed. If a vendor supports more than one inheritance-mapping approach, the vendor usually will have a metadata extension that you can use to specify which approach to use. As you can imagine, only one approach can be used for each inheritance hierarchy.

For a class in an inheritance hierarchy, when the fields of an instance are mapped to multiple tables, the columns containing the instance's identity value need to exist in each table used to represent the class. So, when you use the first inheritance-mapping approach, an instance of C1 has the same primary-key value in the tables that correspond to classes A, B1, and C1. Some implementations let you specify the names of the primary-key columns for each table used in the inheritance hierarchy.