Concepts - Entity inheritance and relational models

Preface

This section describes the phenomenon called 'entity inheritance' and its connection with relational models and the physical data model. It presents two typical entity scenarios and offers insight in how these scenarios are represented in a physical model. Mapping an entity hierarchy in LLBLGen Pro is discussed by describing the most common ways of mapping entity hierarchies onto tables / views and which of these are supported by LLBLGen Pro. The approach of this section is based on: "why would you use it, and if you want to use it, how would you implement it", to make it more understandable why entity inheritance can help you with your project and also for which inheritance can be helpful and thus for which situations you also might want to consider another approach.

Supertypes / subtypes and NIAM terminology

In relational models, entities can derive from another entity, for example to specialize the definition of that other entity. Typically the derived entity is called a subtype and the entity derived from is called a supertype. LLBLGen Pro uses this same terminology. An entity which has subtypes, is called a supertype, and an entity which is a derived entity is called a subtype. In the following sections, two hierarchy types are described which are typical for many situations. The hierarchy types are illustrated with a (simplified) NIAM / ORM (object role modelling: http://www.orm.net). To help the readers who aren't familiar with NIAM and / or ORM, the following brief description should help understand the presented diagrams.

NIAM/ORM diagrams are based on sentences, which are readable in the diagram, and which are called 'facts'. Entities are represented by oval objects with a solid border. Entity attributes (fields) are represented by oval objects with a dashed border. Relations between entities or entities and attributes are represented by an '--[   |   ]--' object, as illustrated in the following examples. A supertype/subtype hierarchy is represented by an arrow, starting at the subtype, pointing to the supertype.



One to many relation, which is mandatory on both elements




One to one relation, between an entity (mandatory) and an attribute


Hierarchy creation for proper entity relation modelling

First an example of a hierarchy which is constructed to utilize proper entity relation modelling:


This model is a simplified NIAM/ORM model, which is a bit larger than shown here (the other part is described in the next sub-section), which illustrates three entity types in an inheritance hierarchy( Employee, Manager and BoardMember) and different relations per entity. The common attributes for all entities in the hierarchy are defined with relations to Employee, which is the root of the hierarchy. The diagram further shows a relation between Employee with Department which illustrates the semantic "Employee works for Department" relation. Manager and BoardMember also have relations, which are specific for their type: Manager has also a relation with Department, but for the semantic relation "Manager manages Department". BoardMember has a relation with CompanyCar, to illustrate the semantic relation "BoardMember has a CompanyCar". These relations are with other entities.

To use the last mentioned relation, BoardMember has a CompanyCar, as an example: this relation is defined on the entity "BoardMember" because only BoardMembers are allowed to have a company car, in this situation. Would the relation be placed on Employee, every employee would, in theory, be able to have a related CompanyCar entity, and thus a company car. There are two main ways to construct a physical representation in tables from a hierarchy like this example:
  1. One table, which contains all fields/attributes of all entities in the hierarchy.
  2. Every entity its own table, which contain only the fields of the particular entity
(Of course, for 'table' you can say 'view')
The first way, which is called in LLBLGen Pro TargetPerEntityHierarchy and which is discussed more in the next subsection, will define the aforementioned relation "BoardMember has a CompanyCar" on the same table / view as where normal employees are stored. This can be a problem, as it's then up to program logic to limit the insertion of employee data so a normal employee can't have a company car. A better approach in this situation, is the second option, where for each entity in the hierarchy a table/view is created and on the BoardMember table the relation to CompanyCar is defined. This second way is called TargetPerEntity in LLBLGen Pro.
Physical representation in the data model and LLBLGen Pro entities
The typical hierarchy mentioned above is realized in your datamodel with one table / view per entity. This means that for the hierarchy above you'll get an Employee table / view, a Manager table / view and a BoardMember table / view. The Employee table is the leading table, where you define the primary key for the entity to uniquely identify an entity instance in the database. As ID is a perfect candidate for this (1:1 relation between entity Employee and attribute) this will become the primary key. Manager and BoardMember get this same field, to identity the rows stored in these tables, though they're not new PK values, but have a foreign key constraint defined to the ID of the supertype, so Manager.ID has a foreign key constraint to Employee.ID and BoardMember has a foreign key constraint to Manager.ID. This way, referential integrity rules in the database make sure your data stored in the database is correct, also for derived entities. Often O/R mappers require a discriminator column in the root table/view so they can determine what the type is of the data the root table/view is holding. In LLBLGen Pro you don't need to define a discriminator column on the root table, LLBLGen Pro can find out by itself what the type is of the data stored in the tables / views which make up a hierarchy.

note Note:
Don't use surrogate keys on the subtype tables, it's important the PK of the subtype tables has the foreign key to the supertype's PK.

Entities
In LLBLGen Pro you can define the same hierarchy as defined above, by simply making Manager a subtype of Employee and BoardMember a subtype of Manager. You can also let LLBLGen Pro try to find these hierarchies for you, by selecting the 'Construct Target-per-entity hierarchies' option in the Entities context menu. When you save a new entity which is a subtype and which is represented in the database by multiple tables, like for example the BoardMember entity, the entity will get a record in all the tables of the hierarchy: Employee, Manager and BoardMember. Updating such an entity will update its rows in the tables where changed fields are located. So if you change BoardMember.Name, an update statement will be issued on the Employee table. Fetching a BoardMember will cause LLBLGen Pro to use INNER JOINs between Employee, Manager and BoardMember. It's important to note that you can't re-use a record in a supertype table for a different subtype instance. For example if you store 'shared' information in the Employee table record, you can't share that record with different Manager instances for example. See also Limitations and Pitfalls later in this section.

Hierarchy creation for proper entity field availability modelling

Following is an example of a hierarchy which is constructed to have different field availability in the different entities in the hierarchy:


This model is part of the bigger NIAM/ORM model presented in the previous subsection. At first it looks like the same type of hierarchy as the previous example however there's a small, but important, difference: the relations presented in this example are between an entity and an attribute. This means that this hierarchy specifies the specialisation of an entity for the purpose of adding different fields to the entity, without polluting the supertype with these fields. In this example, the supertype CompanyCar, which has a relation with BoardMember, is specialized with a DrawingHook attribute in the FamilyCar entity. The SportsCar entity has an extra attribute as well: a Cabrio attribute. Would you not have inheritance, you had to add these attributes to the CompanyCar entity and set them to NULL accordingly. This is a bit inconvenient, because a sportscar obviously never has a drawinghook (ok, some people are that crazy).

In the two main ways to construct a physical representation in tables, you can opt for both ways for this hierarchy, however it's more efficient to use the first hierarchy, because you work on a single table and you don't need foreign keys to preserve referential integrity with related entities defined on subtypes: the relations with subtypes are defined in the root of the hierarchy, CompanyCar.
Physical representation in the data model and LLBLGen Pro entities
The typical hierarchy mentioned above is realized by simply flattening the hierarchy and store all attributes of all the entities in the hierarchy in a single table. Every attribute of the root entity is defined as mandatory (not nullable), while every attribute of a subtype is defined nullable. To be able to determine what the entity type is of a given row in the table / view, a discriminator column is used with a value which represents the type. This column can be of any type, as long as it ends up as a System.Byte/Int16/Int32/Int64/Guid/Decimal or System.String type in LLBLGen Pro. An example for the discriminator column for the hierarchy in this subsection could be the column called 'CarType' of type int, which for example contains '1' for CompanyCar instances, '2' for FamilyCar instances and '3' for SportsCar instances.

Entities
In LLBLGen Pro you can define the same hierarchy by creating subtypes of the CompanyCar entity (or subtypes of subtypes in that hierarchy). As soon as an entity which isn't in a hierarchy, is made root of a hierarchy of type TargetPerEntityHierarchy, all fields which are nullable and not part of a relation are unmapped in the root entity, and can be mapped manually in subtypes. You can of course remap them in the root entity if you want / need to, however typically nullable fields in the root entity are used for fields in subtypes so to save you some work, LLBLGen Pro unmaps them for you first. A dialog helps you defining subtypes and specifying discriminator columns. New entities which are in a TargetPerEntityHierarchy hierarchy don't have to get their Discriminator field set to a value, this is done for you by LLBLGen Pro.

Comparison of inheritance mapping with competing O/R mappers

Inheritance is an important part of most modern O/R mapper frameworks. Because O/R mapping is a generic technique with a wide variety of detailed descriptions, it can be confusing what each mapping strategy means and how it compares to another O/R mapper's way of mapping inheritance.

There are in general 4 ways to map entity / class hierarchies (inheritance hierarchies) onto a set of tables / views:
  1. Complete hierarchy mapped onto a single table. In LLBLGen Pro this is called TargetPerEntityHierarchy. This is the inheritance type which is very easy to implement and therefore supported by most O/R mappers.
  2. Every type in a hierarchy mapped onto its own table, no discriminator column. In LLBLGen Pro this is called TargetPerEntity. This inheritance type is hard to implement, most O/R mappers fall back to option 3.
  3. Every type in a hierarchy mapped onto its own table, with discriminator column in root type. Similar to option 2, and because LLBLGen Pro doesn't need a discriminator column for option 2, this type is supported but the discriminator column is ignored / not required.
  4. Every type in a hierarchy mapped onto its own table, where all fields from the supertype are present in each entity's table. The O/R mappers which do support this mapping call it Target per concrete entity. As it has severe limitations, and is not efficient (both for saves/updates and for data storage) this setup is not supported by LLBLGen Pro.

Abstract entities

It can be that you've defined a hierarchy, for example the Employee, Manager, BoardMember hierarchy, and you don't want the developers of your team to use every type in that hierarchy, for example because one or more types in the hierarchy, like Employee, is defined just to define attributes for the rest of the hierarchy, not to be a real entity. LLBLGen Pro lets you specify if an entity is abstract or not, you do that in the entity editor. Entities which have subtypes and which don't have a supertype which isn't abstract, can be made abstract. An abstract entity means that you can have instances of that entity in multi-entity polymorphic fetches but you can't instantiate an entity instance in code by using its constructor.

Limitations and pitfalls

Entity inheritance is a powerful instrument and can bring you a lot of advantages when working with plain relational data. It also comes with a warning label, as it does require you to think through your physical datamodel before proceeding, and can have performance limitations. LLBLGen Pro's inheritance implementation, while powerful, also has some limitations which most likely won't affect you in your work, but are worth mentioning.
Pitfalls with inheritance
Limitations of the LLBLGen Pro entity inheritance implementation.

LLBLGen Pro v2.6 documentation. ©2002-2008 Solutions Design