Benefits of Lightweight ORM Technology

Benefits of Lightweight ORM Technology

Benefits of Lightweight ORM Technology

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 like Oracle, SQL Server, MySQL, Postgres, and SQLite. However, integrating such applications with a relational database is a big programming challenge because it 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; and manually writing the verbose mapping logic between the object-oriented and relational artifacts is tedious and time-consuming. Using Object Relational Mapping (ORM) frameworks has become a preferred method for developers to simplify the programming efforts of integrating object-oriented applications with relational databases.

Software Tree has developed innovative, flexible, and lightweight Object Relational Mapping (ORM) framework products — JDX for Java, NJDX for .NET, and JDXA for Android — with more ORMs in the pipeline. The underlying ORM technology is based on some well thought-out KISS (Keep It Simple and Straightforward) principles. This blog post explains what we mean when we say that our ORM technology is lightweight. What are the different lightweight aspects of our ORM technology in terms of its composition, its specification, its dependencies, and most importantly its usage? From these explanations, you will also learn why those lightweight aspects matter for application developers and the resulting benefits.

The composition (internal implementation) of our ORM frameworks is lightweight.

The internal design and implementation of our ORM frameworks is highly modular, refactored, and compact. These frameworks consist of reusable and easily extensible components which minimize the code size as well as the code path lengths. Consequently, our ORM libraries have small footprints: 493 KB for JDX, 400 KB for NJDX, and 270 KB for JDXA.

The small footprints of our ORM libraries require less memory and enable their faster loading and execution.

The modular design of our ORM frameworks also makes them more robust and easier to evolve.

The design of our ORM frameworks is lightweight.

Our ORM frameworks are non-intrusive to the persistent object model. This non-intrusiveness provides a lightweight feel to the application developers as the ORM-specific artifacts don’t seep into the object model.

  • No need to inherit persistent classes from a base class.
  • No need to clutter your source code with annotations.
  • Every developer need not be concerned with the ORM aspects. Developers can concentrate on the business logic.
  • Clean architecture — your POJO code does not need to change because the ORM does not do any code generation or byte code enhancements, so your applications are easy to debug.
  • Even JSON objects can be persisted easily.

The ORM specification is lightweight.

The ORM specification is defined declaratively in a simple textual way.

  • Compact; most default mapping is automatically deduced; avoids verbosity.
  • Easy to specify, modify, comprehend, and share. Only one place to look at the mapping — it is not distributed all over in multiple files.
  • Human readable — no XML complexity.
  • Mapping can evolve independently without changing the persistent classes (e.g. table names and column names can be changed in the mapping specification without affecting the source code).
  • Since the source files need not change, the ORM products can work with pre-existing object classes whose source code may not be available or cannot be changed.

Not being an overarching framework, our ORM technology feels lightweight.

Our ORM technology does not bite into the application architecture, resulting in a clean design and implementation of the data integration layer.

  • The ORM system follows a de-coupled approach.
  • The ORM does not trap the application in its tentacles.
  • The mapping engine is fairly stateless.
  • No overhead and confusion because of object change tracking, whose semantics can be complex.
  • The objects can be moved around in different application tiers without any ORM implications.
  • No complex coding and semantics for detach/attach operations.
  • Simple and flexible APIs.
  • No separate query APIs to learn.

The steps for development, integration, and deployment with our ORM technology are lightweight.

The development methodology with our ORMs is simple and lightweight — define persistent classes, define a declarative ORM specification, and use a small set of simple ORM APIs.

  • No extra steps to pre-process, generate, or augment the source code or byte code.
  • No dependencies on other libraries except for a standard database driver.
  • Ideal for providing lightweight persistence functionality in the cloud and with microservices.

In summary, Software Tree’s KISS ORM technology frameworks are lightweight in their design and implementation and provide a lightweight feel in their usage. The lightweight aspects of our ORM technology do not compromise on its power and functionality, though. This results in faster development and deployment of modern applications that require flexible object-oriented access to relational data.

The lightweight nature of our ORMs also makes it easy to integrate them with other tools, frameworks, platforms, Docker containers, IoT software, and microservices.

Learn more about the KISS ORMs, including how to get free trial versions, by visiting Software Tree’s website at https://www.softwaretree.com/.

Posted in Uncategorized | Tagged , , , , , , , , , , , , , , , , | Leave a comment

KISS Principle #1 for ORMs

KISS Principle #1 for ORMs

Solve the most important problem (object relational impedance mismatch) in the simplest possible way.

The most important problem for developers is writing and maintaining endless lines of complex JDBC/ADO.NET/SQL code to exchange data between their business model objects and their relational artifacts (tables, constraints, stored procedures, etc.). Make solving that problem the main focus of the Object Relational Mapping (ORM) product.

Advantages: The ORM product focuses on the most important problem and solves it efficiently.

Software Tree’s Object Relational Mapping (ORM) products follow this KISS Principle #1. Improve developer productivity using these ORMs, JDX for Java, NJDX for .NET, and JDXA for Android.

Learn more about the KISS ORMs, including how to get free trial versions, by visiting Software Tree’s website at http://www.softwaretree.com.

Posted in Uncategorized | Tagged , , , , , , , , , , , , , , | Leave a comment

Some Best Practices for Defining ORM Specifications

Some Best Practices for Defining ORM Specifications
An Object Relational Mapping (ORM) specification consists of mapping specifications for various object classes of an application needing persistence in a relational database. Following the KISS Principle #5 for ORM products, an ORM specification for Software Tree’s ORM products (JDX for Java, JDXA for Android, and NJDX for .NET) is defined declaratively in a text file. Keeping the ORM specification in a textual mapping file separate from the corresponding object class definitions (source files) is an important decoupling principle. This technique also avoids cluttering source files with mapping specification- related annotations or code. Here we discuss how to best order mapping specifications of different classes in a mapping file.

Our KISS Object Relational Mapping (ORM) products read a declarative ORM specification from a mapping file to initialize a mapping engine that performs various object persistence operations per the ORM specification. If needed, our products can make multiple passes over an ORM specification to deal with the mappings for various classes that may be specified in any order and could involve cross-references. However, to help in understanding, maintaining, and evolving an ORM specification more easily, here are some guidelines:

  • Declare the mapping specification of an ELEMENT_CLASS (A) before declaring the mapping specification of a COLLECTION_CLASS (B) or a JOIN_COLLECTION_CLASS (C) involving that ELEMENT_CLASS (A)
  • Declare the mapping specification of a JOIN_CLASS (P) before declaring the mapping specification of a JOIN_COLLECTION_CLASS (Q) involving that JOIN_CLASS (P)
  • Declare the mapping specification of a referenced class (X) before declaring the mapping specification of a referencing class (Y) referencing that class (X) using the REFERENCES keyword in a RELATIONSHIP specification. The referenced class (X) may be a normal CLASS or a COLLECTION_CLASS or a JOIN_COLLECTION_CLASS. This may not always be possible if there are cross-referencing relationships but that is OK; our ORM products can handle that unavoidable ordering.

Essentially, try to declare something before using it. It is like we are making trees going from top to bottom, that is, from leaves to intermediate nodes to roots. In this analogy, a leaf is a standalone CLASS without any RELATIONSHIPs.
In other words, if we were to write the mapping specification on a long piece of paper and draw the following arrows, they should all preferably be pointing upwards:

  • From a COLLECTION_CLASS to its ELEMENT_CLASS
  • From a JOIN_COLLECTION_CLASS to its ELEMENT_CLASS or to its JOIN_CLASS
  • From a referencing CLASS to its REFERENCEd classes

Also, for easier comprehension, it is good to keep the following arrangement:

  • mapping of an element class above and close to the mapping of the corresponding collection class
  • mapping of a join class above and close to the mapping of the corresponding join collection class
  • mapping of a referenced classes above and close to the mapping of a class using those referenced classes.

Some Best Practices for Defining ORM Specifications

Simply put, try to make those upward arrows as short as possible.

Here is a pseudo example of a harder to understand ORM specification.

Bad Mapping SpecHarder To Understand ORM Specification

And here is an example of the same ORM specification with an easier to understand ordering of the mapping specifications.

Good Mapping SpecEasier To Understand ORM Specification

In summary, defining the mapping specification of a dependent class soon after defining the mapping specification(s) of the class(es) it depends on helps you more easily comprehend and evolve an ORM specification. This also optimizes the initialization process of an ORM engine as it may be able to avoid multiple passes of the ORM specification.

Learn more about the KISS ORMs, including how to get free trial versions, by visiting Software Tree’s website at https://www.softwaretree.com.

Posted in Uncategorized | Tagged , , , , , , , , , , , | Leave a comment

INLINE Mapping with JDXA ORM

INLINE Mapping with JDXA ORM

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.

employee-address

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.

public class Employee {
private String id;
private String name;
private String title;
private Address address;


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

public class Address {
private String addr1;
private String addr2;
private String city;
private String state;
private String zip;
private String country;


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

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.

inline-mapping

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.

CLASS Employee
PRIMARY_KEY id
RELATIONSHIP address REFERENCES Address INLINE AUTO_INSTANTIATE
SQLMAP FOR address.addr2 COLUMN_NAME county NULLABLE
;
CLASS Address
PRIMARY_KEY addr1
;

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:

String employeeClassName = Employee.class.getName();

// First delete all existing employees from the database.
// This will also delete the corresponding Address objects.
jdxHelper.delete2(employeeClassName, null);

// Create and insert Employee objects along with the associated
// Address objects.
// Because the address attribute of the Employee class is
// declared as an INLINE attribute in the mapping specification,
// the values of the attributes of an Address object will be
// stored in the same row of the same table where the attributes
// of the containing Employee object are stored.
Address addr1 = new Address(
“111 Main Street”, null, “New York”, “NY”, “10001”, “USA”);
Employee emp1 = new Employee (“E1”, “John Smith”, “Manager”, addr1);

jdxHelper.insert(emp1, true);

// Now create and insert multiple Employee objects along with their
// associated Address objects in one call to JDX.
ArrayList <Employee> employees = new ArrayList<Employee>();

Address addr2 = new Address(
“1-13 St Giles High”, null, “London”, “WC-2H”, “8AG”, “UK”);
Address emp2 = new Address (“E2”, “Mark Clinton”, “Engineer”, addr2);
employees.add(emp2);

Address addr3 = new Address(
“333 City Blvd”, “Apt 33”, “San Francisco”, “CA”, “94103”, “USA”);
Employee emp3 = new Employee (“E3”, “Bob Brown”, “Consultant”, addr3);
employees.add(emp3);

jdxHelper.insert(employees, true);

// Retrieve all the Employee objects
List queryResults = jdxHelper.getObjects(employeeClassName, null);

// Retrieve an Employee (E2) object using its id
Employee emp = (Employee) jdxHelper.getObjectById(
employeeClassName, “empId=E2”, false, null);


// Retrieve all the Employee objects whose country is USA.
// Notice the use of a path expression (address.country='USA')
// in the predicate below.
queryResults = jdxHelper.getObjects(
employeeClassName, "address.country='USA'");

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 https://www.softwaretree.com.

Posted in Uncategorized | Tagged , , , , , , , , , , , , , , , , | Leave a comment

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 https://www.softwaretree.com.

Posted in Uncategorized | Tagged , , , , , , , , , , , , , | Leave a comment

Bulk Deep Delete Operations with JDXA ORM

BulkDelete
How can you make JDXA ORM delete multiple objects along with related objects (bulk deep delete)?

One of the great benefits of using an ORM product like JDXA is being able to use simple object-oriented APIs to handle persistence of model objects in your app. An app not only needs to save and update model objects in a database, but also occasionally needs to get rid of obsolete/unwanted objects from the database. This article describes how multiple objects along with their associated objects can easily be deleted from the database using JDXA ORM.

Consider TripMaster, a hypothetical Android app used to manage trip-related information. TripMaster has, among other classes, the following model classes: Trip, Destination, and Address. As shown in the class definitions below, Trip has a one-to-many relationship with Destination and Destination has a one-to-one relationship with Address.

Suppose you as an app developer want to give user an option to delete one or more Trip objects along with all of the related Destination and Address objects. Essentially, data from three underlying database tables will need to be deleted. One can retrieve a Trip object and the associated Destination objects and the associated Address objects and delete them one by one in reverse order. But is there an easier and faster way to do that with JDXA? Let’s explore the scenario in some detail.

Here are the representative model class definitions (in a package com.tripmaster.model).
Other constructors and setter/getter methods are not mentioned for brevity:

public class Trip { // A trip with multiple destinations
private int tripId;
private String tripName;
private String purpose; // pleasure, business, …
List destinations;

public Trip() {
}
}

public class Destination { // In a trip
private int destinationId;
private int tripId;
private String city;
private String lodgingType; // friend, hotel, airbnb, …
private Address address;

public Destination() {
}
}

public class Address { // At a destination
private int destinationId;
private String addr1;
private String addr2;
private String city;
private String state;
private String zip;
private String Country;

public Address() {
}
}

The objects of the above three classes are persisted in three different database tables as per the ORM specification defined below:

JDX_OBJECT_MODEL_PACKAGE com.tripmaster.model
;
CLASS .Address
PRIMARY_KEY destinationId
SQLMAP FOR addr2 NULLABLE
;
CLASS .Destination
PRIMARY_KEY destinationId
RELATIONSHIP address REFERENCES .Address BYVALUE WITH destinationId
;
COLLECTION_CLASS ListDestinations COLLECTION_TYPE JAVACOLLECTION
ELEMENT_CLASS .Destination
PRIMARY_KEY tripId
;
CLASS .Trip
PRIMARY_KEY tripId
RELATIONSHIP destinations REFERENCES ListDestinations BYVALUE WITH tripId
;

With the above class definitions and ORM specification, it is extremely easy to perform bulk deep delete operations with JDXA ORM. Since we have already defined a BYVALUE relationship between a trip and its destinations and between a destination and its address in the mapping specification, you can use JDXA’s delete2 method to deletethe entire object graph of the qualifying trip objects with one call.
For example:

String tripClassName = Trip.class.getName();

// deep delete a particular trip (e.g., tripId = 5)
jdxHelper.delete2(tripClassName, “tripId=5”);

// deep delete many trips (e.g., tripId < 10)
jdxHelper.delete2(tripClassName, “tripId < 10”);

// deep delete all the trips
jdxHelper.delete2(tripClassName, null);

Alternatively, if you already have one or more persistent objects in memory and want to delete them from the database, just pass those objects to the delete method.
For example:

List trips;
// initialize trips with one or more persistent objects
// deep delete all the given Trip objects
jdxHelper.delete(trips, true);

JDXA also provides the option of dynamically specifying the portions of the object graph to perform a delete operation on (directed operations).

Antibiotics was prescribed to my grandfather already twice. When the grandfather’s temperature rises and the prostatitis worsens, it means that the infection appeared in the body, and it needs to be eradicated only with antibiotics at https://mckesson.uk/antibiotics/. Already on the second day, the temperature fell.

JDXA also supports bulk insert and bulk update operations along with many flexible and convenient query operations for your model objects.

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

Posted in Uncategorized | Tagged , , , , , , | Leave a comment

Generating Unique Ids for Primary Key values using JDXA ORM

primary-key-img

Using primary keys to uniquely identify persistent objects is a fundamental requirement for all apps. A primary key may consist of only one attribute, or it may consist of multiple attributes (composite primary key). The data type of a primary key attribute is typically “int” or “long” but it could also be “String”. For example, a UUID string may serve as a primary key attribute value. JDXA, an innovative Object Relational Mapping (ORM) product, can handle both single attribute and composite primary keys.

A primary key value may be readily available from the data source from which a persistent object is created in an app. For example, data for an object may be retrieved from a server and that data may also contain the primary key value. If the primary key value for a new object is not available from the data source, it needs to be somehow generated as part of the persistence mechanism.

In this article, we will primarily discuss a few techniques for generating primary key attribute values in which the primary key consists of only one attribute whose data type is “int” or “long”. Incidentally, with the unique sequence generator feature of JDXA (described below), one may also create a “String” value for a primary key attribute by concatenating the “long” value returned by a sequence generator with some other text. The article ends with pros and cons of using these different techniques.

With regard to generating unique primary key values of persistent objects, some parts of the following discussion assume that JDXA ORM is used with a SQLite database. However, these techniques may also work with other databases if the databases provide a similar functionality (e.g., an AUTOINCREMENT column).

Let’s assume the following definition of a persistent class Employee, where the id attribute serves as the primary key:

public class Employee {
private int id;
private String name;
private Date DOB;
private boolean exempt;
private float compensation;

/**
* Default no-arg constructor needed for JDX
*/
public Employee() {
}
// Other constructors and accessor (setter/getter) methods omitted

CASE A

In this case, we want the SQLite database to generate the primary key (id) value with an AUTOINCREMENT column.

  • Define the mapping specification for the Employee class as follows:
    CLASS Employee
    PRIMARY_KEY id
    SQLMAP FOR id SQLTYPE 'INTEGER PRIMARY KEY AUTOINCREMENT'
    RDBMS_GENERATED id
    ;

    Note: You need to specify the RDBMS_GENERATED statement in order to tell JDXA that the values of the specified attributes (e.g., id) will automatically be generated by the underlying database.

  • Now, when you insert (save) an Employee object whose id attribute has not been initialized before the insert operation, you have two options:
    1. Ask JDXA to initialize the id attribute of the in-memory Employee object with the RDBMS-generated (AUTOINCREMENT) column value (CASE A1).
      You can do this by using a flag value of JDXS.IFLAG_INIT_WITH_RDBMS_GENERATED_PKEY_VALUE when invoking the insert method. For example,
      Employee emp = new Employee("Mark", …);
      jdxHandle.insert(emp,
      JDXS.IFLAG_INIT_WITH_RDBMS_GENERATED_PKEY_VALUE, null);

      Alternatively, you may also invoke a newly provided insert method in the JDXHelper class:

      jdxHelper.insert(emp,
      JDXS.IFLAG_INIT_WITH_RDBMS_GENERATED_PKEY_VALUE);
    2. Ask JDXA to not initialize the id attribute of the in-memory Employee object with the RDBMS-generated (AUTOINCREMENT) column value (CASE A2).
      This is the default behavior if you don’t use the flag JDXS.IFLAG_INIT_WITH_RDBMS_GENERATED_PKEY_VALUE when invoking the insert method. For example,
      Employee emp = new Employee("Mark", …);
      jdxHandle.insert(emp, 0, null);

      Alternatively, you may also invoke a newly provided insert method in the JDXHelper class:

      jdxHelper.insert(emp, 0);

      You may also use the existing insert method of JDXHelper as follows:

      jdxHelper.insert(emp, true);

CASE B

In this case, we don’t want the SQLite database to generate the primary key (id) value with an AUTOINCREMENT column.

You may use the JDXA-provided named sequence generator feature to efficiently generate unique ids, which you can assign to your objects before saving them in the database (CASE B1).

  • Define the mapping specification with a sequence generator as follows:
    CLASS Employee
    PRIMARY_KEY id
    ;
    SEQUENCE EmpIdSequence MAX_INCREMENT 10

    Note: EmpIdSequence is the name of the JDXA sequence generator. You may tweak the MAX_INCREMENT value to a higher or lower number depending on how many unique ids you would need to generate in a typical session of your app and how many unique ids you want to reserve in the database at a time.

  • Now, when you want to insert (save) an Employee object whose primary key (id) attribute has not been initialized before the insert operation, you may invoke the getNextSeq() method to obtain a unique id and assign it the id attribute as follows:
    // Initialize a sequence generator for EmpIdSequence such that it
    // can provide 5 unique sequence id values before going to the
    // database for the next set of 5 unique id values. Here the increment
    // value is 5. By the way, the maximum increment value can be 10 in
    // this case per the mapping definition of EmpIdSequence
    JDXSeqUtil empSeqUtil = new JDXSeqUtil("EmpIdSequence", jdxSetup, 5);

    // Create and save a few Employee objects
    Employee emp = new Employee("Mark", …);
    emp.setId(empSeqUtil.getNextSeq());
    jdxHandle.insert(emp, 0, null);emp = new Employee("Bob", …);
    emp.setId(empSeqUtil.getNextSeq());
    jdxHandle.insert(emp, 0, null);

    Notes:
    The sequence increment value of 5 may be changed depending on the needs of your app per session. The higher the value, the more efficient the sequence generation operation would be because it would require fewer database trips to fetch (reserve) the next set of unique sequences. However, since any unused sequence values in this session will be unavailable (lost) for the next session, you may not want to use a very high increment value.

    You may pass the empSeqUtil.getNextSeq()value directly to a constructor of the Employee class instead of using the setId() method.

She prescribed me a quarter of a pill Klonopin by https://foamcast.org/klonopin-clonazepam/ at bedtime. I started drinking and the drug suited me perfectly. The drug is beginning to act somewhere with an hour and a half. The drug is pleasantly relaxing. After a while the anxiety recedes, the sweating of the palms disappears, at the same time the tremor goes away. Those who suffer from VSD will understand me perfectly.

Pros and Cons of different techniques for primary key generation:

CASE A1

Using AUTOINCREMENT database column: JDXA initializes the primary key attribute with the database-generated column value.

Pros:
The database-generated primary key attribute value is immediately available for use in the app after the object is inserted (saved).

Cons:
There is a performance penalty as JDXA has to perform an additional database call to obtain the value of the AUTOINCREMENT column after inserting other column values of the object.

CASE A2

Using AUTOINCREMENT database column: JDXA does not initialize the primary key attribute with the database-generated column value.

Pros:
There is a performance benefit as JDXA does not have to perform an additional database call to obtain the value of the AUTOINCREMENT column after inserting other column values of the object.

Cons:
The database-generated primary key attribute value is not immediately available for use in the app after the object is inserted (saved). This may not matter if the app does not need the primary key value right away. Moreover, if the object is subsequently fetched from the database using a query, it would come with its primary key attribute value properly initialized.

CASE B1

Using a JDXA provided named sequence generator: programmatically generating and assigning the unique ids to the primary key attributes.

Pros:
There is a performance benefit as JDXA can efficiently dispense many unique sequence ids before making a database trip for the next set of unique sequence ids.

The primary key attribute values are immediately available for use in the app before the object is inserted (saved). Such values may be used to initialize foreign key attributes in related objects.

Compared to using the AUTOINCREMENT column feature, the JDXA sequence generator feature (with a large increment value) should provide better performance. That’s because, without using the JDXA sequence generator feature, the database has to go through the overhead of generating a unique id for an AUTOINCREMENT column every time a new row (object) is inserted.

Cons:
There is some additional (though very minimal) programming code that must be written to define a sequence generator in the mapping specification and then to use it in the app.

Using primary keys to uniquely identify persistent objects is an important requirement for all apps. JDXA, a simple yet powerful, and non-intrusive ORM for Android, provides many flexible and efficient ways to handle primary keys depending upon the application needs. Learn more about JDXA, including how to get a free trial version, by visiting Software Tree’s website at https://www.softwaretree.com.

Posted in Uncategorized | Tagged , , , , , , , , , , | 2 Comments

Welcome

Welcome to Software Tree blogs! Since Object Relational Mapping (ORM) is the main focus of Software Tree’s products (JDX for Java, NJDX for .NET, and JDXA for Android), we will mostly be discussing ORM related topics here.

Posted in Uncategorized | Tagged , , , , , , , | Leave a comment