ONJava.com -- The Independent Source for Enterprise Java
oreilly.comSafari Books Online.Conferences.

advertisement

AddThis Social Bookmark Button

Object-Relational Mapping with Apache Jakarta OJB
Pages: 1, 2, 3

2.3 Mapping Inheritance

Here comes the real meat of the example. There are three common techniques to map component inheritance to relational tables. They are:



  1. Map each class onto a distinct table, each with its own base class attributes.

  2. Map all classes in a hierarchy onto one table.

  3. Map each class into a distinct table, each with a foreign key to its base class table, where base class attributes can be found.

Each technique has its own pros and cons. In the following sections, we will discuss each one of them in detail.

2.3.1 One Table Per Class


2.3.1.1 Table Schema

This technique puts all base class attributes into the subclass tables. The base class table and the subclass table are not related in the schema.

Example 3: Table Schema For Mapping Strategy One

CREATE TABLE employee (
  id   INTEGER NOT NULL,
  name VARCHAR(50) NOT NULL,
  PRIMARY KEY (id)
);

CREATE TABLE manager (
  id             INTEGER NOT NULL,
  name           VARCHAR(50) NOT NULL,
  project_number INTEGER NOT NULL,
  PRIMARY KEY (id)
);

2.3.1.2 Implementation

The implementation is straightforward and requires no special OJB changes:

Example 4: Implementations For Mapping Strategy One


public class EmployeeImpl extends BasePersistenceObjectImpl implements Employee
{
    private String name;

    public void setName(String name)
    {
        this.name = name;
    }

    public String getName()
    {
        return name;
    }
}

public class ManagerImpl extends EmployeeImpl implements Manager
{
    private Integer projectNumber;

    public ManagerImpl()
    {
        super();
    }

    public Integer getProjectNumber()
    {
        return projectNumber;
    }

    public void setProjectNumber(Integer projectNumber)
    {
        this.projectNumber = projectNumber;
    }
}

2.3.1.3 OJB Descriptor

The OJB descriptor describes how a Java class and its attributes map to a table. In OJB, we denote inheritance using the <extent-class> element in the descriptor file. In this case, EmployeeImpl is the base class of ManagerImpl. Once the extent-class is in place, if a query is performed against EmployeeImpl, objects that extend EmployeeImpl (e.g. ManagerImpl) will also be considered for matching.

Example 5: OJB Descriptor For Mapping Strategy One

<class-descriptor class="ojbtest.impl.distinct.EmployeeImpl"
                  table="EMPLOYEE">
  <extent-class class-ref="ojbtest.impl.distinct.ManagerImpl"/>
  <field-descriptor id="1"
                    name="id"
                    column="ID"
                    jdbc-type="INTEGER"
                    primarykey="true"
                    autoincrement="true"/>
  <field-descriptor id="2"
                    name="name"
                    column="NAME"
                    jdbc-type="VARCHAR"/>
</class-descriptor>

<class-descriptor class="ojbtest.impl.distinct.ManagerImpl"
                  table="MANAGER">
  <field-descriptor id="1"
                    name="id"
                    column="ID"
                    jdbc-type="INTEGER"
                    primarykey="true"
                    autoincrement="true"/>
  <field-descriptor id="2"
                    name="name"
                    column="NAME"
                    jdbc-type="VARCHAR"/>
  <field-descriptor id="3"
                    name="projectNumber"
                    column="PROJECT_NUMBER"
                    jdbc-type="INTEGER"/>
</class-descriptor>

2.3.1.4 Pros & Cons

This approach has two main advantages. First, the table schemas are separated cleanly. No joins are necessary to query one type of object. Second, database constraints can be applied.

Despite these advantages, this approach suffers from performance problems. Consider the case when you need to query all Employees. Both the MANAGER table and the EMPLOYEE table will be queried. The performance penalty grows proportionally to the size of the class hierarchy. Also, the duplicated base class columns in each subclass table make adding an attribute to the base class more difficult.

2.3.2 One Table Per Class Hierarchy


2.3.2.1 Table Schema

With this technique, the base class and all of its subclasses are stored in one table. The table schema contains attributes of all classes in the same hierarchy:

Table 6: Table Schemas For Mapping Strategy Two

CREATE TABLE employee (
  id             INTEGER NOT NULL,
  class_name     VARCHAR(255),
  name           VARCHAR(50) NOT NULL,
  project_number INTEGER,
  PRIMARY KEY (id)
);

Notice that a new column, CLASS_NAME, is used by OJB to identify the type of object a table row represents.

2.3.2.2 Implementation

To use this mapping technique, OJB requires a special attribute (ojbConcreteClass) in your base class. This special attribute must be initialized to the proper subclass class name during object initialization.

Example 7: Implementations For Mapping Strategy Two

public class EmployeeImpl extends BasePersistenceObjectImpl implements Employee
{
    /** the special attribute telling OJB the object's concrete type.
     *  NOTE: this attribute MUST be called ojbConcreteClass
     */
    protected String ojbConcreteClass;
    private String name;

    public String getOjbConcreteClass()
    {
        return ojbConcreteClass;
    }

    public void setOjbConcreteClass(String ojbConcreteClass)
    {
        this.ojbConcreteClass = ojbConcreteClass;
    }

    public void setName(String name)
    {
        this.name = name;
    }

    public String getName()
    {
        return name;
    }
}

public class ManagerImpl extends EmployeeImpl implements Manager
{
    private Integer projectNumber;

    public ManagerImpl()
    {
        super();
        ojbConcreteClass = ManagerImpl.class.getName();
    }

    public Integer getProjectNumber()
    {
        return projectNumber;
    }

    public void setProjectNumber(Integer projectNumber)
    {
        this.projectNumber = projectNumber;
    }
}

2.3.2.3 OJB Descriptor

In the descriptor, we specify that the ojbConcreteClass attribute is mapped to the CLASS_NAME table column. This allows queries to return objects of the right type:

Table 8: OJB Descriptor For Mapping Strategy Two

<class-descriptor class="ojbtest.impl.hierarchy.EmployeeImpl"
                  table="EMPLOYEE">
  <extent-class class-ref="ojbtest.impl.hierarchy.ManagerImpl"/>
  <field-descriptor id="1"
                    name="id"
                    column="ID"
                    jdbc-type="INTEGER"
                    primarykey="true"
                    autoincrement="true"/>
  <field-descriptor id="2"
                    name="ojbConcreteClass"
                    column="CLASS_NAME"
                    jdbc-type="VARCHAR"/>
  <field-descriptor id="3"
                    name="name"
                    column="NAME"
                    jdbc-type="VARCHAR"/>
</class-descriptor>

<class-descriptor class="ojbtest.impl.hierarchy.ManagerImpl"
                  table="EMPLOYEE">
  <field-descriptor id="1"
                    name="id"
                    column="ID"
                    jdbc-type="INTEGER"
                    primarykey="true"
                    autoincrement="true"/>
  <field-descriptor id="2"
                    name="ojbConcreteClass"
                    column="CLASS_NAME"
                    jdbc-type="VARCHAR"/>
  <field-descriptor id="3"
                    name="name"
                    column="NAME"
                    jdbc-type="VARCHAR"/>
  <field-descriptor id="4"
                    name="projectNumber"
                    column="PROJECT_NUMBER"
                    jdbc-type="INTEGER"/>
</class-descriptor>

2.3.2.4 Pros & Cons

This approach has two main advantages. First, no table joins are necessary to query objects in the same hierarchy. Second, adding a new class to the hierarchy has very little overhead.

This approach has its own problems, though. For example, database constraints must be relaxed to accommodate all attributes in the class hierarchy. Also, it is not easy to identify from the table schema which attributes belong to which class.

2.3.3 One Table Per Class, with a Foreign Key to the Base Class

This technique creates a table for each class in the hierarchy. Unlike the first approach, the base class attributes are not duplicated in the subclass tables. Instead, each subclass table uses a special foreign key to refer back to the base class. OJB does not directly support this model.

This technique has two main advantages. First, the subclass tables do not duplicate any base class columns. Second, database constraints can be applied.

However, this technique suffers from excessive table joins in queries. The performance gets worse as the class hierarchy deepens.

After evaluating your options, you can decide which mapping technique suits you best. The next step in our example is to create the OJB deployment descriptor.

Pages: 1, 2, 3

Next Pagearrow