This section provides a high-level overview of Embedded Database Object (EDO) technology and why it is important to the Aptify Framework.
It covers the following topics:
- About the Problem Leading to EDO
- About the EDO Solution
- About the Optional Embedded Objects
- About the Types of Embedded Objects
About the Problem Leading to EDO
In many business applications there are situations where tables of data contain common repeating patterns of information that are not best managed if stored redundantly in each table. A good example of this is address information. There are many business cases that result in logical data models, including address information in entity designs. For example, address information is logically associated with Organizations, Employees, Persons, Companies, Orders, Subscriptions, and more.
In Aptify 3.x and prior versions, this information was maintained separately in each table in order to simplify the development and report-writing aspects of the data model. Added normalization in a data model usually comes at a cost in the area of reporting ease of use, performance for queries, and programmatic complexity when working with the data model. On the other hand, added normalization generally will improve transactional performance due to smaller table sizes and more efficient data storage patterns.
One of the design goals for the Aptify 4.x and 5.x framework technologies was to enable application developers, including the developers of Aptify's own CRM and Membership suite, to pursue a more normalized data model while at the same time maintaining the ease of programmatic and reporting access that has been enjoyed in all prior versions of the technology. For example, consider the following scenario:
In an application, a developer chooses to create a normalized Address table which will be used in all areas of a system that need to store Address data, including a Customer table and an Orders table.
A simplified version of the schema might look something like this:
The challenge to the developer is that all transactions that relate to a Customers or Orders record in the above model would require managing records in both the Customers/Orders table as well as one or more records in the Addresses table. In addition, it is critical that the transaction management around these multiple inserts/updates be managed properly so that an update to a customer profile happens in its entirety as part of a commit.
In addition, report writers must join in multiple tables for common report writing requirements, such as to create simple rosters or label reports on a Customers record. This complexity is particularly problematic for many of the report writers who do not have substantial database experience and fit the description of a power-user more than a database administrator or programmer.
About the Optional Embedded Objects
There are cases when a foreign key relationship is established as an optional relationship between records. For example, a company may or may not have a Billing Address that is different from its primary address. In those types of scenarios, an embedded object may or may not exist for a given foreign key in the Generic Entity (GE) object model.
The GE object model optimizes the loading of embedded objects when a containing object is first loaded. For example, if a Company GE object is loaded up, only the Company GE object itself is loaded into memory initially. The virtual fields associated with the CompanyGE are available for read access without needing to access the embedded GE object since those values are carried in the Company GE itself as virtual fields.
The embedded GE is loaded up only if a change is being made to an embedded object, or if a user's code directly requests the underlying embedded object through the Dot syntax method or direct embedded object access. This approach is completely transparent to developers that are using the GE but is important to be aware of since it improves performance of the GE object loading and saving by a considerable margin.
To determine whether an embedded object has been loaded by the GE, check the AptifyDataFieldBase.EmbeddedObjectExists function. This function is used by the parent GE object to determine whether or not the Embedded GE object has been loaded. It returns True if the Embedded object has been instantiated and False otherwise. See the Aptify Software Development Kit (SDK) for more information.
The EmbeddedObjectExists function provides a valuable service since the Embedded GE object will only be loaded when it is required. If the parent GE identifies that the Embedded record has not been loaded, which means it has not been changed, no further interaction is required, and the parent GE can optimize its Validation and Save operations. Conversely, if you access the AptifyDataFieldBase.EmbeddedObject method, the system will load the Embedded GE object each time, even when it is not necessary.
About the Types of Embedded Objects
Aptify offers two implementations of Embedded Data Objects: Non-Shared and Shared.
Non-Shared Embedded Objects
A non-shared object is an embedded link that provides a one-to-one relationship between the parent record and the embedded record. For example, in Aptify, the Message Parts service has an embedded, non-shared link to the Scripts service, since a particular script corresponds to a single Message Parts record. See Creating Non-Shared Embedded Objects for information on how to create a non-shared embedded link.
Shared Embedded Objects
A shared embedded object corresponds to an embedded record that may be linked to multiple records. For example, consider the example of an application that includes a Companies entity and a Persons entity that are used to manage customers at the organizational and individual level. Companies and individuals frequently share address information. Using a normalized model such as the one described in Understanding the Embedded Object Model, it is possible to link a company and its individuals directly to the same record in the Addresses table. This would reduce the number of records in the system and also speed up transactional performance when adding new persons to an existing company since a new record would not need to be inserted into the Addresses table. Furthermore, space requirements in the database would be reduced in this model and when an address is changed at the company level, it would automatically be reflected in all persons linked to the same physical Addresses record.
While this type of data modeling is desirable in some areas of a database, it can be undesirable in others. In some applications and in some table relationships it may be necessary for a record to have exclusive ownership of an embedded object. In that case, the concept of sharing would not be used at all.
For example, in the case where a company and multiple persons linked to it are sharing an address, if an individual within the company has a unique address, it is important that the unique address of that individual be respected and not overwritten when a company's address changes. The rest of the individuals linked to the company should get the new company address automatically, but an individual that previously had a different address than the company address should retain that unique address.
This type of functionality has existed in the Aptify CRM and Membership applications in several relationship areas including Companies/Persons and Organizations/Employees. However, in prior versions of the business applications, this flow-down actually was a physical flow-down of data from the Companies record to the Persons record and from the Organizations record to the Employees record. Whenever a company's address was changed, each person linked to the company was evaluated, and if the address at the person level was the same as the old company address, a flow-down occurred.
This type of business application functionality is commonplace and desirable at a logical level. In Aptify, embedded object sharing supports this scenario, but through a much more efficient process. Rather than physically flowing down data, records can be shared and therefore automatic "flow-downs" occur since Persons and Companies that are intended to share an address are linked to the same Addresses record.
If all shared embedded object scenarios desired to have complete auto-flow-down of data, then the concept of sharing embedded objects would be a simple one to implement. All the users would need to do is link in the same embedded object primary key value into multiple "container" records. Whenever any such container record made a change to the embedded object, all other container records would automatically get the change. The problem, of course, is this is not always desired. In some cases, the desire is for the "flow" to occur only in one direction — from Company to Person, but not the other way.
Therefore, Aptify's shared embedded implementation also deals with these types of situations where an automatic record update is not desired, such as when a person has a different address than his or her company or when an order has an address specified as a Ship To destination.
Shared embedded objects eliminate the need for many custom flow-down scenarios in business application code and also can increase the efficiency of common transactions, such as changing an address of a company that might have many individuals linked to it. See Designing and Creating Shared Embedded Objects for more information on shared embedded links and their implementation.