Inheritance Support in JDXA ORM

Inheritance-img
The Joys of Inheritance

Inheritance is an important and useful concept in object-oriented programming. Inheritance promotes the reuse of the functionality of existing components and makes the resulting program (application) more modular, easily understandable, and extensible. This post gives a brief introduction to the concept of inheritance and explains how JDXA, the KISS ORM for Android, can easily handle the persistence of objects involved in inheritance relationships.

In programming terms, an inheritance relationship between two object classes is established when one class (a subclass), in addition to defining its own attributes and methods, “inherits” the attributes and methods of another class (a superclass). In the Java language terminology, a subclass extends a superclass. Semantically, one may say that an instance of a subclass is also an instance of its superclass. Moreover, a subclass may be a superclass of yet another class. This kind of inheritance relationship amongst different classes creates a class hierarchy. For example, one may have the following class hierarchy in the domain model of an application:

Person is the superclass with BaseEmployee and Intern as its subclasses.
BaseEmployee has two subclasses – PermEmployee and TempEmployee.
Diagrammatically, this class hierarchy may be depicted in the following way:

person-img

Based on the above class inheritance structure, one may say that an instance of Intern is also an instance of Person (i.e., an Intern is a Person). Similarly, an instance of PermEmployee is also an instance of BaseEmployee. One may even say that an instance of TempEmployee is also an instance of Person.

A relational database is a preferred repository for the domain model objects of an application. An Object Relational Mapper (ORM) is typically used to simplify the writing of programming code needed to accomplish the saving and retrieval of domain model objects using a relational database (e.g., SQLite on the Android platform).

However, an ORM solution has to be fairly sophisticated to be able to persist (save) and retrieve objects in a class hierarchy.  For example, an ORM solution should provide a simple and flexible way to define the underlying database table structure necessary to store objects of the class hierarchy. It should also provide simple and flexible APIs to save and retrieve (query) those objects, which may even be involved in relationships with other objects. Furthermore, an ORM should also provide a mechanism to retrieve only the objects of a top-level class if so desired.

With respect to the above domain model classes, if a query is made for Person objects, the ORM should also retrieve all the qualifying objects of all the subclasses (Intern, BaseEmployee, PermEmployee, and TempEmployee) from the database.  Similarly, if a query is made for BaseEmployee objects, the ORM should also retrieve the qualifying objects of the PermEmployee and TempEmployee classes. One should also be able to optionally retrieve only the Person objects that were originally saved as Person objects (and not saved as, for example, Intern objects).

As explained below, JDXA ORM provides simple and flexible mechanisms for defining the mapping for a domain model class hierarchy declaratively. JDXA also provides simple and flexible APIs for saving and querying objects of a class hierarchy.

Here are some high-level code snippets for defining the domain model classes, specifying the mapping specification, and using the JDXA ORM APIs.

In the domain model class definitions below, the code for accessor (getters/setters) methods has been omitted for brevity.

public class Person {
  private int id;
  private String name;
  private Date DOB;

  /**
  * Default no-arg constructor needed for JDXA
  */
  public Person() {
  }
}
public class Intern extends Person {
  private String school;

  /**
  * Default no-arg constructor needed for JDX
  */
  public Intern() {
  }
}
public class BaseEmployee extends Person {
  private String dept;

  /**
  * Default no-arg constructor needed for JDX
  */
  public BaseEmployee() {
  }
}
public class PermEmployee extends BaseEmployee {
  int salary;

  /**
  * Default no-arg constructor needed for JDX
  */
  public PermEmployee() {
  }
}
public class TempEmployee extends BaseEmployee {
  private float hourlyRate;

  /**
  * Default no-arg constructor needed for JDX
  */
  public TempEmployee() {
  }
}

Here is the JDXA ORM mapping specification for the domain model classes defined above:

CLASS Person
  PRIMARY_KEY id
;

CLASS Intern
  PRIMARY_KEY id
;

CLASS BaseEmployee
  PRIMARY_KEY id
;

CLASS PermEmployee
  PRIMARY_KEY id
;

CLASS TempEmployee TABLE MyTempEmployee
  PRIMARY_KEY id
;

As you can see, the declarative ORM specification is very simple and succinct. Most of the mapping information is automatically derived by JDXA based on some reasonable conventions. For example, a table name is assumed to be the same as the class name unless it is explicitly overridden (as in the case of the class TempEmployee above).

By default, JDXA stores instances of a class hierarchy in different tables using horizontal partitioning, meaning instances of any particular class are stored in one particular table assigned for that class. JDXA avoids the need for runtime joins by creating a separate subclass table with all the relevant columns needed for that subclass. So, in the above example, the table Intern will have columns for all the attributes of the class Intern, including those attributes inherited from the class Person.

JDXA also supports the option to store the instances of a class hierarchy in an aggregated database table, where an additional discriminating column value is used to identify the class name for the data in a particular row.

By default, a query on a superclass also retrieves the qualifying objects of the subclasses (polymorphism). However, you may restrict the selection to only the superclass objects by using the flag JDXS.QFLAG_PROPER_EXTENT in the query or access method calls.

You may delete multiple objects in a class hierarchy with a single JDXA API call.

Here are some code snippets, with embedded comments, exemplifying the power of JDXA APIs in terms of handling objects in a class hierarchy:

// First populate a few (3) Person objects.
List <Person> persons = new ArrayList <Person>();
persons.add(new Person("Barry", …);
persons.add(new Person("Larry", …);
persons.add(new Person("Mary", ….);
jdxHelper.insert(persons, true);

// Now populate a few (2) Intern objects.
List <Intern> interns = new ArrayList <Intern>();
interns.add(new Intern("Nina", "Stanford", …));
interns.add(new Intern("Elvis", "USC", …));
jdxHelper.insert(interns, true);

// Now populate a few (4) Permanent Employee objects.
List <PermEmployee> permEmployees = new ArrayList <PermEmployee>();
permEmployees.add(new PermEmployee("Barry", "Engg", …));
permEmployees.add(new PermEmployee("Jennifer", "Marketing", …));
permEmployees.add(new PermEmployee("Matt", "Sales", …));
permEmployees.add(new PermEmployee("Howard", "Engg", …));
jdxHelper.insert(permEmployees, true);

// Query all Persons;
// this will polymorphicaly fetch all the nine Person objects including
// objects from all the subclasses
List queryResults = jdxHelper.getObjects(personClassName, null);

// Query all Persons with name >= ‘Mary’;
// this will polymorphically fetch the three objects
//(Person “Mary”, Intern “Nina”,and Permanent Employee “Matt”)
//in the class hierarchy with name >= ’Mary’
queryResults = jdxHelper.getObjects(personClassName, “name >= ’Mary’”);

// Query all Permanent Employees with name >= ‘Mary’;
// this will fetch one Permanent Employee “Matt”
queryResults = jdxHelper.getObjects(permEmployeeClassName, “name >= ’Mary’”);

// Query all Base Employees with name >= ‘Mary’;
// this will fetch one Permanent Employee “Matt”
queryResults = jdxHelper.getObjects(baseEmployeeClassName, “name >= ’Mary’”);

// Query all Permanent Employees in Engg department;
// this will fetch one Permanent Employee “Matt”
queryResults = jdxHelper.getObjects(permEmployeeClassName, “dept = ’Engg’”);

// Query only the objects of the Person class; ignore objects of any subclasses;
// see the flag QFLAG_PROPER_EXTENT;
// this will fetch the one Permanent Employee “Matt”
queryResults = jdxHelper.getObjects(personClassName, null, JDXS.ALL, JDXS.QFLAG_PROPER_EXTENT,…);

// Delete the two objects of the Intern class;
queryResults = jdxHelper.delete2(internClassName, null);

// Delete all the objects of the Person class;
// this will delete all the remaining seven objects in the Person class hierarchy
queryResults = jdxHelper.delete2(personClassName, null);

In summary, inheritance is a very powerful and useful concept in object-oriented programming. Inheritance enables the reuse of code, leading to more modular and compact application design.

JDXA ORM easily and elegantly supports the persistence of objects involved in inheritance relationships with its simple mapping specification and intuitive APIs. The JDXA SDK ships with a detailed sample project demonstrating JDXA’s support of inheritance.

Learn more about JDXA ORM, including how to get a free trial version, by visiting Software Tree’s website at http://www.softwaretree.com.

About Damodar Periwal

Damodar Periwal is the founder of Software Tree. He has an extensive background in databases, transaction processing, as well as distributed and object-oriented technologies. Damodar has more than 25 years of industry experience, having worked at leading companies like Google, TIBCO, Borland, Ashton-Tate, and Tandem Computers. Damodar has an MS (Computer Science) degree from University of Wisconsin (Madison) and an undergraduate engineering degree from Birla Institute of Technology and Science, Pilani (India).
This entry was posted in Uncategorized and tagged , , , , , , , , , , , , , . Bookmark the permalink.

Leave a Reply

Your email address will not be published. Required fields are marked *