Home

Entity Inheritance

From a technical point of view, entity inheritance is of interest to encapsulate basic design concepts in a base class which should apply to various entity types in the same way. The chapter Find and Query already mentioned a few examples like a default public clone() method and a toString() method. Another typical reason is a stereotype set of table rows which should be present in each table like an auto-incremented technical ID, a creation time and a last modification time, or a lock counter for concurrency control by optimistic locking.

As a simple example for inheritance, you can split up the Customer entity in a way that the ID is encapsulated in a separate entity class IdentifiedEntity which the Customer entity is derived from. This is based on the assumption that all entity classes should have a unique ID row which is a wide-spread concept.

Inheritance in PriDE is a bit inconvenient as you have to maintain more than one inheritance hierarchy. However, new tables and entities don’t shoot like mushrooms out of the ground, so there’s no reason to bother. Beside the entities, you also have to relate both entities’ descriptors, and if you are working with separate adapters, the adapter classes have to be derived from each other too. As long as you are using 1:1 mappings, you can let PriDE’s entity generator do most of the job. So here is how to generate the little inheritance hierarchy which you can find in package inheritance in the PriDE manual examples source code repository on GitHub. You start with generating the base class. As the generator is based on table structures in a database and there is no such concept like “base classes” in SQL, you must ensure that the CUSTOMER table is already present (resp. any other table following the same pattern with a technical ID) . To generate a class which does not map all the columns, you specify the columns of interest as comma-separated list along with the table name when calling the generator:

java
util.EntityGeneratorWithExampleConfig
CUSTOMER(ID) inherit.AbstractHybrid > AbstractHybrid.java

The call above uses the class EntityGeneratorWithExampleConfig mentioned at the end of the Quick Start Tutorial to simplify the passing of configuration parameters. Adding column names to a table name, tells the generator, that this is only a partial mapping resulting in an abstract class like this:

abstract public class AbstractHybrid extends MappedObject implements Cloneable, java.io.Serializable {
    public static final String COL_ID = "id";

    protected static final RecordDescriptor red =
      new RecordDescriptor(AbstractHybrid.class, null, null)
            .row( COL_ID, "getId", "setId" )
            .key( COL_ID );

    public RecordDescriptor getDescriptor() { return red; }

    private int id;

    public int getId()   { return id; }
    public void setId(int id) { this.id = id; }

    // Re-constructor
    public AbstractHybrid(int id) throws SQLException {
        setId(id);
        findXE();
    }

    public AbstractHybrid() {}

    public Object clone() throws CloneNotSupportedException {
        return super.clone();
    }

}

Note that there was no table name constant generated and no table name is specified in the RecordDescriptor. All this doesn’t make sense for an abstract base class. The derived Customer class is then generated by specifying the base class in the generator call:

java
util.EntityGeneratorWithExampleConfig
CUSTOMER inherit.DerivedCustomer
-h inherit.AbstractHybrid > DerivedCustomer.java

It is important to know that the call requires the base class to be compiled first. The generator will determine the remaining columns to map from reading the meta data of the CUSTOMER table from the database and the mapping information from the base class as byte code. It is therefore mandatory to specify the base class as fully qualified name even if it resides in the same package. The result looks like this:

public class DerivedCustomer extends inherit.AbstractHybrid {
    public static final String TABLE = "CUSTOMER";
    public static final String COL_NAME = "name";
    public static final String COL_FIRST_NAME = "first_name";

    protected static final RecordDescriptor red =
      new RecordDescriptor(DerivedCustomer.class, TABLE, inherit.AbstractHybrid.red)
        .row(COL_NAME, "getName", "setName")
        .row(COL_FIRST_NAME, "getFirstName", "setFirstName")
        .key( COL_ID );

    public RecordDescriptor getDescriptor() { return red; }

    private String name;
    private String firstName;

    public String getName()   { return name; }
    public String getFirstName()   { return firstName; }

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

    // Re-constructor
    public DerivedCustomer(int id) throws SQLException {
        super(id);
    }

    public DerivedCustomer() {}

}

Note the following details:

The resulting DerivedCustomer class behaves exactly like the Customer class from the Quick Start Tutorial. You can check that by running the CustomerClient from the quick start tutorial in parallel with the equivalent DerivedCustomerClient from the package inherit. Both have the same functionality and operate on the same table but work with the two different entity representations. This reveals an important fact about PriDE’s concept how inheritance is mapped to SQL where you don’t find such a concept. In terms of JPA, PriDE follows the table-per-class strategy. For every non-abstract class in the hierarchy there must exist a database table with columns for all mapped attributes of the class itself and all its super classes.

Inheritance with separate adapters

When you are working with separate adapters, you need a derivation for both, entity class and adapter class. The generator calls look like that:

# Entity base class
java util.EntityGeneratorWithExampleConfig
CUSTOMER(id) inherit.AbstractEntity -b

# Adapter base class
java util.EntityGeneratorWithExampleConfig
CUSTOMER(id) inherit.AbstractAdapter inherit.AbstractEntity

# Derived Customer entity class
java util.EntityGeneratorWithExampleConfig
CUSTOMER inherit.DerivedCustomerEntity -b inherit.AbstractAdapter

# Derived Customer adapter class
java util.EntityGeneratorWithExampleConfig
CUSTOMER inherit.DerivedCustomerAdapter inherit.DerivedCustomerEntity inherit.AbstractAdapter

An important detail is that generating the derived bean class requires to specify the base adapter class, not the base entity class in the generator call. In fact the generator needs to know about both, but the entity class can be determined from the adapter class’ record descriptor. The pure base entity class however doesn’t know about its mapping - that’s lastly the goal of the separation ;-)

The output of these generator calls is a very straight-forward separation of the hybrid code above. There is nothing tricky to know about. You can find the outcome in the package inherit from the PriDE manual examples source code repository on GitHub.

Entity inheritance hierarchies are of course not limited in their depth. E.g. if it were a typical pattern that entities have names, try this command and have a look on the output:

java util.EntityGeneratorWithExampleConfig
CUSTOMER(name) inherit.AbstractNamedHybrid -h inherit.AbstractHybrid

What PriDE does not support are queries based on abstract base entities which automatically consider the tables of the derived non-abstract entities. You can find features like that in JPA, but they require a highly complicated, obscure SQL query assembly - in combination with the table-per-class strategy resulting in SQL union expressions. This is something, which doesn’t happen too often and should always remain in the developer’s responsibility to stay on control of your SQL.