21 Introduction to Relational Descriptors

This chapter provides an overview of relational descriptors, as well as explains the role of inheritance and various types of descriptors in relational projects.

This chapter includes the following sections:

For information on descriptor concepts and features common to more than one type of TopLink descriptors, see Chapter 16, "Introduction to Descriptors".

21.1 Relational Descriptors

Relational descriptors describe Java objects that you map to tables in a relational database. You use them in relational projects (see Chapter 18, "Introduction to Relational Projects").

Using relational descriptors in a relational project, you can configure relational mappings (see Section 27.1, "Relational Mapping Types").

For more information, see the following:

21.2 Aggregate and Composite Descriptors in Relational Projects

In a relational project, you can designate the descriptor as an aggregate (see Section 22.2.1.2, "Creating Relational Aggregate Descriptors").

This lets you configure an aggregate mapping (see Chapter 37, "Configuring a Relational Aggregate Object Mapping") to associate data members in the target object with fields in the source object's underlying database tables.

When you designate a relational descriptor as an aggregate, TopLink lets you specify a mapping type for each field in the target class, but defers associating the field with a database table until you configure the aggregate object mapping in the source descriptor. In other words, the target class descriptor defines how each target class field is mapped, but the source class descriptor defines where each target class field is mapped. This lets you share an aggregate object among many parent descriptors mapped to different tables.

When you designate a relational descriptor as an aggregate, you tell TopLink that the class will be a target of an aggregate object mapping, and this ensures that the TopLink runtime handles the target class as follows:

  • It inserts, updates, and deletes the target class in parallel with its source class.

  • It does not cache the target class on its own; instead, it caches the target class as part of its source class.

  • It does not allow the target class to be read, written, deleted, or registered in a unit of work.

When working with aggregate relational descriptors, consider the following:

For more information, see Section 23.6, "Configuring a Relational Descriptor as a Class or Aggregate Type".

21.2.1 Relational Aggregates and Nesting

TopLink supports nested aggregates. In Figure 21-1 source class HockeyPlayer is a normal nonaggregate class descriptor. It owns target class Info which is designated as an aggregate. The Info class itself owns target classes PersonalInfo and TeamInfo which are each designated as aggregates.

Figure 21-1 Nested Aggregates

Description of Figure 21-1 follows
Description of "Figure 21-1 Nested Aggregates"

In EJB 3.0, an aggregate is known as an embeddable. In the EJB 3.0 specification, an embeddable may not contain another embeddable (that is, the EJB 3.0 specification does not support nested aggregates).

However, if you deploy a TopLink-enabled EJB 3.0 application with persistence to Oracle WebLogic Server, you can take advantage of a EclipseLink extension of the EJB 3.0 specification to configure nested embeddables. Note that if you do so, your application will not be strictly EJB 3.0-compliant. Example 21-1 shows the classes from Figure 21-1 using EJB 3.0 annotations to take advantage of the EclipseLink extension of the EJB 3.0 specification to allow Info (an embeddable) to own embeddables TeamInfo and PersonalInfo.

Example 21-1 Nested Embeddables

public class HockeyPlayer implements Serializable {
    private int playerId;
    private Info Info;
    private String lastName;
    private String firstName;
    ...
    @Embedded
    public Info getInfo() {
        return Info;
    }
}
 
@Embeddable
public class Info implements Serializable {
    TeamInfo teamInfo; // EclipseLink extension of EJB 3.0 allows Embeddable with Embeddable
    PersonalInfo personalInfo;
    
    public Info() {}
    
    @Embedded
    public PersonalInfo getPersonalInfo() {
        return personalInfo;
    }
    
    public void setPersonalInfo(PersonalInfo personalInfo) {
        this.personalInfo = personalInfo;
    }
    
    @Embedded
    public TeamInfo getTeamInfo() {
        return teamInfo;
    }
    
    public void setTeamInfo(TeamInfo teamInfo) {
        this.teamInfo = teamInfo;
    }
}
 
@Embeddable
public class PersonalInfo implements Serializable {
    private int age;
    private double weight;
    private double height;
    ...
}
 
@Embeddable
public class TeamInfo implements Serializable {
    private String position;
    private int jerseyNumber;
    private HockeyTeam hockeyTeam;
    ...
}

21.2.2 Relational Aggregates and Inheritance

You can configure inheritance for a relational descriptor designated as an aggregate (see Section 16.2.2, "Descriptors and Inheritance"), however, in this case, all the descriptors in the inheritance tree must be aggregates. Aggregate and class descriptors cannot exist in the same inheritance tree.

21.2.3 Relational Aggregates and EJB 2.n Entity Beans

You can use relational aggregate descriptors in an EJB project, but you cannot configure EJB information for a relational descriptor designated as an aggregate (see Section 16.2.3, "Descriptors and CMP and BMP").

For information on using relational aggregates and EJB 3.0, see Section 21.2.1, "Relational Aggregates and Nesting".

21.3 Descriptors and Inheritance in Relational Projects

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

This section includes information on the following topics:

For more information, see Section 16.3, "Descriptors and Inheritance".

21.3.1 Inheritance and Primary Keys in Relational Projects

For relational 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.

For more information, see Section 119.2, "Configuring Primary Keys".

21.3.2 Single- and Multi-Table Inheritance in Relational Projects

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

21.3.2.1 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 21-1, "Nested Aggregates" can share the same table, as in Figure 21-2. 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 21-2 shows, this approach uses a class indicator field. For more information, see Section 16.3.1, "How to Specify a Class Indicator".

Figure 21-2 Inheritance Using a Superclass Table with Optional Fields

Description of Figure 21-2 follows
Description of "Figure 21-2 Inheritance Using a Superclass Table with Optional Fields"

21.3.2.2 Multi-Table 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 21-1, "Nested Aggregates", 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 Section 16.3.1, "How to Specify 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 21-3 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 21-3 Inheritance Using Separate Tables for Each Subclass

Description of Figure 21-3 follows
Description of "Figure 21-3 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.
21.3.2.2.1 Inheritance Outer-Joins

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.

By default, TopLink executes multiple queries to read in a multiple table inheritance hierarchy, which, in some cases, is the most efficient way to query. In addition, TopLink supports querying the inheritance hierarchy using a single outer-join query (Section 119.19, "Configuring Reading Subclasses on Queries").

You can also set a database view on the descriptor that outer-joins or unions all of the tables. For more information, see Section 23.7, "Configuring Multitable Information".