Modern application programs are mostly written in object-oriented languages like Java and the business objects (also known as domain model objects) used in those applications are typically stored (persisted) in an SQL relational database. However, integrating such applications with a relational database is a big programming challenge because that entails bridging the gap between the object-oriented world and the relational world which are conceptually different; mixing Java programming with SQL relational language is hard; manually writing the verbose mapping logic between the object-oriented and relational artifacts is tedious and time-consuming. Using Object Relational Mapping (ORM) products has become a preferred way to simplify the development efforts of integrating object-oriented applications with relational databases.
Software Tree has developed innovative and flexible ORM products – JDX for Java, NJDX for .NET, and JDXA for Android. These products are based on some well though-out KISS Principles for ORM detailed here.
JDXA is a simple, non-intrusive, and comprehensive ORM product for the Android platform. JDXA can easily handle complex object models and lets you map them flexibly to a (SQLite) relational database. In this blog, we will discuss the INLINE mapping feature of the JDXA product, which provides the flexibility of optionally storing the attribute values of a contained (referenced) object in the same database table as the one used for storing the attribute values of the containing (referencing) object. This INLINE mapping capability also has the welcome side effect of increasing the efficiency of data access operations, as explained below. Further, JDXA provides the facility of filtering top-level containing objects based on the attribute values of the corresponding INLINEd objects.
N.b. The INLINE feature is also available in the NJDX and JDX products. We may use the product names JDXA and JDX interchangeably in the rest of the article.
For the purpose of explaining the INLINE mapping feature of JDXA ORM, let’s consider the following two object model classes – Employee and Address – where an Address object is referenced by an Employee object in a one-to-one relationship. Segregating an Address class from an Employee class may be desirable from a program design perspective, since these classes represent two different kinds of business entities. Let’s assume that an Address object cannot exist without a referencing Employee object.
The above model classes can be defined in Java as follows. Here, the code for accessor (getters/setters) methods and other constructors has been omitted for brevity.
As per the above class definitions, an Address object from an Employee object is referenced by a non-primitive (complex) attribute named address. Normally, the attribute values of an Employee object will be stored in a row of a different database table than the attribute values of the corresponding Address object and these table rows would need to be linked through a “foreign key” column (attribute) value. But, since we know the semantics of their relationship, that is, an Address object cannot have an existence independent of an Employee object, we may, for the reason of efficiency, want to store the attribute values of both an Employee and the corresponding Address object together in a single record of one database table. Essentially, as shown below, we want to INLINE the storage of Address attribute values with the storage of the corresponding Employee attribute values.
With such an aggregated table layout, the number of database trips to store/retrieve/delete an Employee object along with its related Address object will be reduced in half, as only one table would need to be accessed to get/set/remove the attribute values of the objects of both classes.
As explained below, JDXA ORM provides a simple and flexible mechanism for declaratively defining the INLINE mapping of a contained class. Here is an example of the JDXA mapping specification for the Employee and Address model classes defined above.
JDXA ORM Specification
As you can see, the declarative ORM specification is very simple and succinct. Most of the mapping information is automatically derived by JDX based on some reasonable conventions. For example, a table name is assumed to be the same as the class name and a column name is assumed to be the same as an attribute name unless it is explicitly overridden.
With respect to INLINE mapping of a complex attribute, it is very easy to specify this in the context of the mapping specification for the containing class. As shown above, just mention the keyword INLINE while defining the RELATIONSHIP specification for the address attribute in the mapping specification for the class Employee.
The INLINE keyword means that the attributes of a contained object (e.g., an Address object referenced by the complex attribute address) can be stored in the columns of the same table to which the containing class (e.g., Employee) is mapped. This does not require the use of foreign key attributes. The default column name of an INLINEd attribute is logically patterned like (<complexAttribName>_<attribName>). For example, the default column name of the state attribute in the Employee table would be address_state.
You can also specify SQL column mapping for an INLINEd attribute by using its name with dot notation. For example, the SQLMAP specification for address.addr2 above within the mapping specification of the class Employee means that the addr2 attribute value of the contained Address object may be null. As a result, the corresponding column should be declared NULLable in the database table. The SQLMAP also specifies a non-default column name of “county” for the addr2 attribute.
Based on the above mapping specification, a database table Employee will be created by JDXA with the following column names:
id, name, title, address_addr1, county, address_city, address_state, address_zip, address_country.
Even though the corresponding column name may be different than the dot notation attribute name, the application logic just needs to use the object-oriented pattern of accessing/specifying an attribute, and the JDX ORM layer performs the appropriate translation for accessing the underlying column name. In other words, an application program is totally shielded from the underlying relational schema for the object model.
If AUTO_INSTANTIATE is specified, then during query, JDX instantiates an object of the class Address with its default constructor and assigns it to the INLINE complex attribute address of the containing (Employee) object. If AUTO_INSTANTIATE is not specified, the INLINE complex attribute should be instantiated and initialized in the default constructor of the containing class.
Note that you may not always want to use the INLINE feature because storing attribute values of a contained object in a separate table gives you the ability to query and analyze just the contained objects without the overhead of involving the attribute values of the containing objects.
Here are some code snippets, with embedded comments, exemplifying the power of JDX APIs in terms of handling INLINE relationship mapping described above:
In summary, JDXA ORM supports flexible and optimized storage of INLINE attributes in the same table as the attributes of the containing class, resulting in improved database operation performance in many situations.
JDXA also supports a notion of EMBEDDED complex attributes, whereby all the attributes of the contained object are serialized and put into a blob column of the table to which the containing class is mapped. This may provide an optimized way to store a referenced object if the attributes of the referenced object do not need to be used in a query predicate.
Learn more about the KISS ORMs, JDX and JDXA, including how to get free trial versions, by visiting Software Tree’s website at http://www.softwaretree.com.