Our platform has now established a basic process flow where orders can generate and modify objects via an order service. But if orders modify objects, then the modification itself must be stored in the database before it is applied to the object itself. For example, if we create an order that modifies the name of a person and send that order to the status hold, the modification needs to be stored in the database, while the name of the person itself should remain unchanged until the persistence action of the order gets executed.
There are several ways how to do this, any of which would work just fine. To select a strategy, we want to find a way to store that information in a clean way that still allows for reasonably quick data access. Let us have a look at three approaches and briefly evaluate them:
- One way to store the transient object modification information is to create a transient copy of the object in the OBJ table itself, with a flag of the transient nature of the entry. The order could then reference the transient object. Upon object persistence, the order could copy the information to the original object and delete the “transient” entry. An advantage of this would be, that we only need a few extra columns to manage the transient object. On the downside though, the business meaning of the entity would depend on a context, creating additional effort anywhere else where we need to find objects. We will therefore reject this approach.
- Another approach could be to create a separate table for the object modifications of an order. This way we do not have the “data garbage” in the OBJ table. But we would need an additional entity with an extra join that will cost performance with every database access.
- Lastly, we can store the transient object properties on the order itself. The advantage is, that we do not need an additional table for these attributes. On the downside however, that will also remove the ability to historize the modification itself.
For example: User “Harry” creates an order to generate a new object called “Sorcerer’s stone”. He executes the “store” action that sends that order to the status “hold”. The action does not yet persist the object, but only saves the modification on the order. Now the user “Ron” opens that order, changes the name to “Philosophers stone” and verifies the order. The object will be created with the name “Philosophers stone”. However, we will not be able to see that “Harry” originally intended to give the object another name in that order.
It is a trade-off we are willing to accept. Why?
Because Harry could have verified that order directly. Then Ron could have created a new order to modify that object. That way, the original name Harry intended to add to that object would remain in the object history while the object now would have the updated name. How that object historization will work, will be discussed in the next article.
We have decided where to store the object modifications. If we look at our object again, we see that there are 2 attributes, which we would like to track in case they are modified: The name and the close date. To track their modification in the order, we therefore just add the same properties on the order, but with the pre-fix “OBJ_” to recognise the object properties based on this naming convention.
What if In the future, we will want to be able to track more object properties, like things that are specific to only a certain business type?
An example that comes to mind would be the login-name and password of a user. We could try to simply add all those properties to the “Order” @Entity.
But what if we have 100 Business Types and each business type has 10 additional properties?
Our order @Entity would then generate a table with 1,000 columns. That would quickly become a mess and destroy the structure of our application. Time to find a better approach!
Business type specific objects and orders using inheritance
We now know that we cannot just save every new property we need on the OBJ table. Instead, we want to find a better way. One approach we can and will use for data that we do not need to change frequently is to create additional entities for different property types, like free text fields for notes or categories for reference data like the S&P rating of an asset.
Another strategy that has a higher focus on application performance is to keep critical object properties on the object table. But rather than adding them to the OBJ and ORDER_BASE tables directly, we will use inheritance. Again, following a naming convention, we will create three additional classes for every Business Type that requires performance critical fields:
- An object subclass based on the business type. It will extend the OBJ class and add the object type as a suffix. For example: OBJ_USER extends OBJ
- An order subclass also based on the business type with an equivalent naming convention.
For example: ORDER_USER extends ORDER
- A business type specific order service subclass that assigns the business type specific object fields on the order to the object subclass.
For example: OrderUserSvc extends OrderSvc
Assigning the value will happen in an override of a business type specific field assignment method that is called in the OrderSvc class. The method is a parameterized function receiving the type of both the order and the object. Using parameterization, we can instantiate and cast subclasses to generate entries in the business type specific tables. Here is an example of a service inheriting from the OrderSvc for the USER business type:
The complete implementation of the inheritance framework will not be outlined here since it is rather complex. Instead, let us visualise the inheritance: