Skip Headers
Oracle TopLink Developer's Guide
10g Release 3 (10.1.3)
B13593-01
  Go To Documentation Library
Home
Go To Product List
Solution Area
Go To Table Of Contents
Contents
Go To Index
Index

Previous
Previous
Next
Next
 

Understanding Descriptors and Inheritance

Inheritance describes how a derived class inherits the characteristics of its superclass. You can use descriptors to describe the inheritance relationships between classes in relational, EIS, and XML projects.

Figure 26-2 illustrates the Vehicle object model–a typical Java inheritance hierarchy. The root class Vehicle contains two branch classes: FueledVehicle and NonFueledVehicle. Each branch class contains a leaf class: Car and Bicycle, respectively.

Figure 26-2 Example Inheritance Hierarchy

Description of Figure 26-2  follows
Description of "Figure 26-2 Example Inheritance Hierarchy "

TopLink recognizes the following three types of classes in an inheritance hierarchy:

  1. The root class stores information about all instantiable classes in its subclass hierarchy. By default, queries performed on the root class return instances of the root class and its instantiable subclasses. However, the root class can be configured so queries on it return only instances of itself, without instances of its subclasses.

    For example, the Vehicle class in Figure 26-2 is a root class.

  2. Branch classes have a persistent superclass and also have subclasses. By default, queries performed on the branch class return instances of the branch class and any of its subclasses. However, as with the root class, the branch class can be configured so queries on it return only instances of itself without instances of its subclasses.

    For example, the FueledVehicle class in Figure 26-2 is a branch class.

  3. Leaf classes have a persistent superclass in the hierarchy but do not have subclasses. Queries performed on the leaf class can only return instances of the leaf class.

    For example, the Car class in Figure 26-2 is a leaf class.

In the descriptor for a child class, you can override mappings that have been specified in the descriptor for a parent class, or map attributes that have not been mapped at all in the parent class descriptor.

This section includes information on the following topics:

For more information about configuring inheritance for a parent (root) class descriptor, see "Configuring Inheritance for a Parent (Root) Descriptor".

For more information about configuring inheritance for a child (branch or leaf) class descriptor, see "Configuring Inheritance for a Child (Branch or Leaf) Class Descriptor".

Specifying a Class Indicator

When configuring inheritance, you configure the root class descriptor with the means of determining which subclasses it should instantiate.

You can do this in one of the following ways:


Note:

All leaf classes in the hierarchy must have a class indicator and they must have the same type of class indicator (field or class extraction method).

Using Class Indicator Fields

You can use a persistent attribute of a class to indicate which subclass should be instantiated. For example, in a relational descriptor, you can use a class indicator field in the root class table. The indicator field should not have an associated direct mapping unless it is set to read-only.


Note:

If the indicator field is part of the primary key, define a write-only transformation mapping for the indicator field (see Chapter 48, "Configuring a Relational Transformation Mapping").

You can use strings or numbers as values in the class indicator field.

The root class descriptor must specify how the value in the class indicator field translates into the class to be instantiated.

One approach is to configure the root class descriptor with a class indicator dictionary: a collection of key-values that associates a simple key, stored in the class indicator field, with a class to instantiate. Table 26-3 illustrates the class indicator dictionary for the Vehicle class's subclasses as shown in Figure 26-2.

Table 26-3 Class Indicator Dictionary for the Vehicle Class

Key Value

F

FueledVehicle

N

NonFueledVehicle

C

Car

B

Bicycle


Another approach is to simply use the class name itself as the value stored in the class indicator field. This avoids having to define unique indicators for each class at the expense of a slightly larger key value (depending on the length of your class names).

Using Class Extraction Methods

You can define a Java method to compute the class indicator based on any available information in the object's data source record. Such a method is called a class extraction method.

Using a class extraction method, you do not need to include an explicit class indicator field in your data model and you can handle relationships that are too complex to describe using class indicator fields.

A class extraction method must have the following characteristics:

  • it must be defined on the root descriptor's class

  • it must be static

  • it must take a Record as an argument

  • it must return the java.lang.Class object to use for the Record passed in

You may also need to define only-instances and with-all-subclasses expressions (see "Specifying Expressions for Only-Instances and With-All-Subclasses").

For example, Table 26-4 lists the rows in the EMPLOYEE table. The Employee class is the base class. Director, Manager, Programmer, and TechWriter classes each derive from the Employee class. However, in your application, instances of Manager, Programmer, and TechWriter classes must be represented as Employee instances and instances of Director must be represented as Director instances. Because there is no a one-to-one correspondence between class and JOB_TYPE field value, the JOB_TYPE field alone cannot serve as a class indicator field (see "Using Class Indicator Fields"). To resolve this issue, you could use the class extraction method shown in Example 26-4.

Table 26-4 EMPLOYEE Table

ID NAME JOB_TYPE JOB_TITLE

732

Bob Jones

1

Manager

733

Sarah Smith

3

Technical Writer

734

Ben Ng

2

Director

735

Sally Johnson

3

Programmer


Example 26-4 Class Extraction Method

...
// If the JOB_TYPE field value in record equals 2, return the Director class.
// Return the Employee class for all other JOB_TYPE field values

public static Class getClassFromRecord(Record record)
{
    if (record.get("JOB_TYPE").equals(new Integer(2))
    {
        return Director.class;
    }
    else
    {
        return Employee.class;
    }
}

When configuring inheritance using a class extraction method, Oracle TopLink does not generate SQL for queries on the root class.

Specifying Expressions for Only-Instances and With-All-Subclasses

If you use a class extraction method (see "Using Class Extraction Methods"), you must provide TopLink with expressions to correctly filter sibling instances for all classes that share a common table (see "Configuring Inheritance Expressions for a Parent (Root) Class Descriptor").

Inheritance and Primary Keys (Relational and EIS Only)

For relational and EIS projects, TopLink assumes that all of the classes in an inheritance hierarchy have the same primary key, as set in the root descriptor. Child descriptors associated with data source representations that have different primary keys must define the mapping between the root primary key and the local one.

Single and Multi-Table Inheritance (Relational Only)

In a relational project, you can map your inheritance hierarchy to a single table ("Single Table Inheritance") or to multiple tables ("Multitable Inheritance"). Use these options to achieve the balance between storage efficiency and access efficiency that is appropriate for your application.

Single Table Inheritance

In this example, you store classes with multiple levels of inheritance in a single table to optimize database access speeds.

The entire inheritance hierarchy shown in Figure 26-2 can share the same table, as in Figure 26-3. The FueledVehicle and NonFueledVehicle subclasses can share the same table even though FueledVehicle has some attributes that NonFueledVehicle does not. The NonFueledVehicle instances waste database resources because the database must still allocate space for the unused portion of its row. However, this approach saves on accessing time because there is no need to join to another table to get the additional FueledVehicle information.

As Figure 26-3 shows, this approach uses a class indicator field. For more information, see "Specifying a Class Indicator".

Figure 26-3 Inheritance Using a Superclass Table with Optional Fields

Description of Figure 26-3  follows
Description of "Figure 26-3 Inheritance Using a Superclass Table with Optional Fields"

Multitable Inheritance

In this example, you store classes with multiple levels of inheritance in multiple tables to optimize database storage space.

In the inheritance hierarchy shown in Figure 26-2, for subclasses that require additional attributes, you use multiple tables instead of a single superclass table. This optimizes storage space because there are no unused fields in the database. However, this may affect performance because TopLink must read from more than one table before it can instantiate the object. TopLink first looks at the class indicator field (see "Specifying a Class Indicator") to determine the class of object to create, then uses the descriptor for that class to read from the subclass tables.

Figure 26-4 illustrates the TopLink implementation of the FUELEDVHCL, CAR, and BICYCLE tables. All objects are stored in the VEHICLE table. FueledVehicle, Car, and Bicycle information are also stored in secondary tables. Note that because the NonFueledVehicle class does not hold any attributes or relationships, it does not need a secondary table.

Figure 26-4 Inheritance Using Separate Tables for Each Subclass

Description of Figure 26-4  follows
Description of "Figure 26-4 Inheritance Using Separate Tables for Each Subclass"


Note:

. In general, using multitable inheritance is inefficient because it can require excessive joins and multiple table fetching.

Inheritance View

If a root or branch inheritance descriptor has subclasses that span multiple tables, you can configure a database view to optimize the performance of queries against the parent descriptor by outer-joining all of the subclass tables. This allows TopLink to fetch all of the subclass instances in one query, instead of multiple queries. It also allows queries for the parent class that use cursors or ordering.

You must define the view on the database as a database view that outer-joins all of the subclass tables. For more information, see "Configuring Reading Subclasses on Queries".

Aggregate and Composite Descriptors and Inheritance

You can designate relational descriptors as aggregates, and EIS descriptors as composites. XML descriptors are always composites (see "Descriptors and Aggregation").

When configuring inheritance for a relational aggregate descriptor, all the descriptors in the inheritance tree must be aggregates. The descriptors for aggregate and non-aggregate classes cannot exist in the same inheritance tree.

Similarly, when configuring inheritance for an EIS composite descriptor, all the descriptors in the inheritance tree must be composites. The descriptors for composite and noncomposite classes cannot exist in the same inheritance tree.

When configuring inheritance for an XML descriptor, because all XML descriptors are composites, descriptor type does not restrict inheritance.

Inheritance and EJB

Although inheritance is a standard tool in object-oriented modeling, the current EJB specification contains only general information regarding inheritance. You should fully understand this information before implementing EJB inheritance. Be aware of the fact that the next EJB specification may dictate inheritance guidelines not supported by all application servers.