Copyright © Mats Helander 2004
By: Mats Helander
Mapping Class Inheritance Hierarchies with NPersist
Non-Primary Tables and Properties
Specifying Inheritance in the NPersist XML Mapping File
Substituting Inheritance for Association
Implementing Single Table Inheritance
Implementing Class Table Inheritance
Implementing Concrete Table Inheritance
Implementing Polymorphic Relationships
This document describes how you can map class inheritance hierarchies in your persistent object model to a table or tables in your relational database using the NPersist framework.
First of all, though, a word of caution: Don’t be “trigger-happy” with inheritance in your persistent object models. It is not recommended that you use inheritance to implement such a trivial example as we are going to use in this document in your real projects.
Use inheritance when you really need it and it really makes sense. Beware that with persistent objects, the types of situations that call for inheritance are not the same as in your other class structures.
This document will not cover the when and where of using inheritance in your persistent object model. It will only note that using inheritance is way less often appropriate in your persistent object model than in your other, non-persistent class structures.
The reason is that using inheritance is normally associated with (sometimes hefty) performance penalties and/or wasted space in the database. Thus, use inheritance in your persistent object model with care.
Having said that, mapping inheritance hierarchies is sometimes just what you want to do, and of course NPersist will let you do so.
Here is the example class hierarchy that will be used in this document, and which we will see how we can map to the database using a few different approaches.
Fig 1 – A Class Inheritance Hierarchy
As mentioned, this might be a reasonable class hierarchy for a bunch on non-persistent objects, but it is not recommended that you actually go ahead and implement this hierarchy with persistent objects in any real project.
While the hierarchy will do for the purpose of illustration, we will go on to look at alternatives to inheritance that are often more suitable for persistent objects.
But first we will look at some of the concepts that will be relevant when we go on to see how NPersist lets you map your inheritance hierarchies to the database.
There are three major patterns for mapping class inheritance hierarchies to a relational database. In his book, Patterns of Enterprise Application Architecture, Martin Fowler offers the following three names for these patterns: SingleTableInheritance, ClassTableInheritance and ConcreteTableInheritance.
All three of these major inheritance patterns are supported by the NPersist framework.
With the SingleTableInheritance pattern, all the classes in the hierarchy are mapped to a single table in the database. With the other two patterns, several tables are used to accommodate the class hierarchy.
While to a certain extent these three patterns can be mixed within a hierarchy, this document will not cover how that is done or when it applies. In this document, it is assumed that a single pattern is chosen for mapping all the classes in the hierarchy to the database.
Assume that we add another class to our model. This class is not a subclass in our hierarchy. We call the class Dog and in addition to a Name and a Color property we create a reference property called BelongsTo that will hold a reference to the person that the dog belongs to.
Fig 2 – A Polymorphic Relationship
The data type of the BelongsTo property is specified as Person which means that any object of the class Person or any of its subclasses is considered as a valid value for the property. In other words, the BelongsTo property must be able to hold a reference to an object that can be a Person, an Employee, a Customer or a ValuedCustomer. screen aspire
As far as your persistent objects are concerned, this isn’t a problem: this is just how the .NET type system works. You’ll be able to pass an object of the Person class or any of its subclasses to the BelongsTo property and no exception will be thrown.
The problems start when we have to map polymorphic relationships to the database. Very briefly, the problems can be summed up as the BelongsTo property potentially having to look in several different tables (four, in our case) to find its referenced objects.
In order to solve these problems, NPersist uses a variation on the second two patterns, ClassTableInheritance and ConcreteTableInheritance, diverging slightly from the way the patterns are described by Martin Fowler in his book and the way these patterns are implemented in many other O/R Mapping frameworks.
NPersist uses the concept of Primary and Non-Primary (sometimes called Secondary) tables and properties, which will be explained now.
Each persistent class must map to at least one table in the database. This table is called the primary table for the class.
Normally, most or all of the properties in the class will map to columns in this table, but some properties can be configured to map to columns in other tables. Such a table is called a non-primary table for the class and such a property is called a non-primary property.
So, if we have a persistent Dog class that maps to the tblDogs table in the database, tblDogs is the primary table for the Dog class.
The tblDogs table has two columns called Name and Color and the Dog class has two properties with the same names mapping to these columns. Since they are mapping to columns in the primary table for the class, they are “ordinary” primary properties.
Note that the Identity property or properties (The property/properties mapping to the primary key column/columns in the table - in this case the property mapping to the Name column) must always be primary properties.
But say that we have another table, called tblDogDescriptions, with two columns called Name and Description. The Name column is both the primary key for the table as well as a foreign key pointing at the Name column in the tblDogs table.
One way to map this would be to create another class called DogDescription and let it map to the tblDogDescriptions table. The Dog class could then get a DogDescription reference property holding a reference to the DogDescription object belonging to the Dog object. To see the description for your dog, you’d write:
myDog.DogDescription.Description
But the NPersist non-primary property support also lets you create a Description property right in your Dog class and let it map directly to the Description column in the tblDogDescriptions table, allowing you to write just:
myDog.Description
Fig 3 – Non-primary property mapping to non-primary table in the database
The Dog.Decription property would be an example of a non-primary property and the tblDogDescriptions table is a non-primary table for the Dog class.
There can be many different reasons to use the support for non-primary properties, but as we shall see soon it is very relevant here since this feature becomes central to the way NPersist solves ClassTableInheritance and ConcreteTableInheritance.
Non-primary properties are always considered Lazy Loading by NPersist, which means that the value for the property is not loaded from the database until the property is accessed for the first time.
Note, however, that whenever you read any of an object’s non-primary properties mapping to a certain non-primary table, all the non-primary properties mapping to the same table will be loaded in the same go, in this way minimizing the number of calls to the database.
<ClassMap>
<Name>Dog</Name>
<Table>tblDogs</Table>
...
<PropertyMaps>
<PropertyMap>
<Name>Name</Name>
<IsIdentity>true</IsIdentity>
<Column>Name</Column>
...
</PropertyMap>
<PropertyMap>
<Name>Color</Name>
<Column>Color</Column>
...
</PropertyMap>
<PropertyMap>
<Name>Description</Name>
<Table>tblDogDescriptions</Table>
<Column>Description</Column>
...
</PropertyMap>
</PropertyMaps>
</ClassMap>
Listing 1 – NPersist XML Mapping for non-primary property
Type columns (sometimes called type discriminator columns) are used when mapping several classes to the same table in the database.
For example, say that we store our Person objects and our Employee objects as rows in the same table, tblPersons. So, how can we tell if a given row is a saved Person object or a saved Employee object?
Well, we can do it by adding an additional column to the table and saying that for a Person object, the row should have the letter P in this column while an Employee object should have the letter E.
This additional column is the type column and P and E are the type values for the Person and Employee classes.
Normally type columns are only used with the SingleTableInheritance pattern, but in the NPersist variation on the other two inheritance patterns a type column is used for those as well.
The NPersist XML Mapping File is where you describe your persistent classes, the tables in the database and the Object/Relational Mapping information relating the classes to the tables using an XML format that the NPersist framework can understand.
In order to specify that a class inherits from another class, you have to do two things:
Furthermore, there are two more Object/Relational Mapping settings that need to be specified for all three inheritance patterns:
Depending on the inheritance pattern used, you may then have to enter additional Object/Relational Mapping settings for your classes and properties, but these are the steps that are common to all three patterns.
<ClassMap>
<Name>Person</Name>
<Table>tblPersons</Table>
<InheritsClass></InheritsClass>
<InheritanceType>SingleTableInheritance</InheritanceType>
<TypeColumn>PersonType</TypeColumn>
<TypeValue>P</TypeValue>
...
</ClassMap>
<ClassMap>
<Name>Employee</Name>
<Table>tblPersons</Table>
<InheritsClass>Person</InheritsClass>
<InheritanceType>SingleTableInheritance</InheritanceType>
<TypeColumn>PersonType</TypeColumn>
<TypeValue>E</TypeValue>
...
</ClassMap>
Listing 2 – Mapping class inheritance in the NPersist XML Mapping File
When you let your objects inherit from each other, they inherit each others’ properties. For example, the Employee class in our example doesn’t only have the Salary and EmploymentDate properties that you see in the figure. It also inherits the Id, FirstName and LastName properties from the Person class.
A corresponding thing occurs when NPersist reads your XML Mapping File. When you specify in your mapping file that a class inherits from another class, the subclass will inherit the settings for the properties of the super class.
Behind the covers, when the NPersist framework looks for the XML Mapping information for a property and can’t find it, it will check to see if the super class contains any mapping information for the property and continue upwards in the class hierarchy until the XML Mapping information for the property is found.
For example, say that you have added the XML for describing the three properties of the Person class under the XML element for your Person class in your NPersist XML Mapping file.
Then, in the XML element for your Employee class, you specify that it inherits from the Person class. Now, as you do this, you will not have to enter any XML for describing the three Person properties under the XML element for your Employee class.
<ClassMap>
<Name>Person</Name>
...
<PropertyMaps>
<PropertyMap>
<Name>Id</Name>
<IsIdentity>true</IsIdentity>
<Column>PersonId</Column>
...
</PropertyMap>
<PropertyMap>
<Name>FirstName</Name>
<Column>FirstName</Column>
...
</PropertyMap>
<PropertyMap>
<Name>LastName</Name>
<Column>LastName</Column>
...
</PropertyMap>
</PropertyMaps>
</ClassMap>
<ClassMap>
<Name>Employee</Name>
<InheritsClass>Person</InheritsClass>
...
<PropertyMaps>
<PropertyMap>
<Name>Salary</Name>
<Column>Salary</Column>
...
</PropertyMap>
</PropertyMaps>
</ClassMap>
Listing 3 – Property mapping settings are inherited in the NPersist XML Mapping File
However, you can enter the XML for the Person properties under the XML element for your Employee class too if you want to. This is called Property Shadowing. If you do this, the NPersist framework will find the XML Information for the property in the subclass first and not continue looking in the super classes.
One reason to do this is if some Object/Relational Mapping settings have to be modified for a property in a subclass.
For example, say that the FirstName property of the Person class maps to a column called FName but the inherited FirstName property of the Employee object should map to a column called FN (for some reason).
In order to solve this, we just enter the XML for the FirstName property under the XML element for both the Person and the Employee classes.
In the XML we enter under the element for the Person class, we enter the value FName in the Column element. In the XML we enter under the element for the Employee class, we enter the value FN in the Column element.
<ClassMap>
<Name>Person</Name>
...
<PropertyMaps>
<PropertyMap>
<Name>Id</Name>
<IsIdentity>true</IsIdentity>
<Column>PersonId</Column>
...
</PropertyMap>
<PropertyMap>
<Name>FirstName</Name>
<Column>FName</Column>
...
</PropertyMap>
<PropertyMap>
<Name>LastName</Name>
<Column>LastName</Column>
...
</PropertyMap>
</PropertyMaps>
</ClassMap>
<ClassMap>
<Name>Employee</Name>
<InheritsClass>Person</InheritsClass>
...
<PropertyMaps>
<PropertyMap>
<Name>FirstName</Name>
<Column>FN</Column>
...
</PropertyMap>
<PropertyMap>
<Name>Salary</Name>
<Column>Salary</Column>
...
</PropertyMap>
</PropertyMaps>
</ClassMap>
Listing 4 – Shadowing the property mapping settings for the FirstName property
As mentioned, inheritance in a persistent class model should be used very sparingly. It is often costly as far as performance goes as well as somewhat complicated to use.
So, what are the alternatives? Well, the most obvious one is to trade the Is-a relationship for a Has-a relationship.
Is-a and Has-a are terms describing inheritance and just plain references, respectively. In our example hierarchy,
So, instead of letting the Employee class inherit from the Person class, you could just let the Employee class hold a reference to a Person object using a reference property.
By substituting inheritance for association between the objects in this way, you can achieve many of the benefits of inheritance in your persistent object model without going through the trouble of learning how to deal with “real” inheritance.
One of the common reasons to use inheritance is that you have two classes that share a set of properties. Rather than implementing these properties separately in each class, you let one class inherit from the other – or both classes inherit from a common base class that you create and which holds the shared properties.
However, due to the increased complexity inherent in mapping inheritance hierarchies to relational database tables, the option of implementing the properties separately for both classes rather than using inheritance is worth consideration for persistent objects. This approach will also perform better than most mapped inheritance hierarchies. learn italian on ipad
Ok, enough of how not to use inheritance, let get right on with how to use it.
The first pattern that we will look at is SingleTableInheritance.
Fig 4 – Single Table Inheritance
With this pattern, all the classes in a hierarchy are mapping to the same table, usually named after the root class in the hierarchy.
In order to know which class in the hierarchy an object that has been stored in a certain row belongs to, a type column is used. Each class in the hierarchy has its own type value, which must be unique within the hierarchy and is stored in the type column when an object is saved to the table.
In our example, storing a Person object to the table would mean that the letter P would be saved to the PersonType type column, while storing an Employee object would result in an E in the type column.
Together with the column or columns mapped to by the identity property/properties the type column should form a composite primary key for the table.
The table must have columns for all the properties of all the classes in the hierarchy. This means that when saving an object high up in the hierarchy (for example a Person object) many of the columns will go unused in the resulting row in the table.
This implies that the columns representing properties in subclasses must be set up to allow NULL values.
Since there’s only one table, all the classes in the hierarchy will consider this table as their primary table.
SingleTableInheritance is arguably the most straight-forward to use of the three patterns, and it often gives the best performance.
Drawbacks include wasted space on the database hard disk for the columns that go unused and that you must let columns for properties in subclasses accept null values.
Furthermore, if you have a large hierarchy that together have a great many properties when all added up, the result is a table with a whole lot of columns, which can be undesirable.
A bonus though is that the mapping information you have to enter in your NPersist XML mapping file when using SingleTableInheritance is not very complicated.
You just map all the classes in the hierarchy to the same table using the Table element for each class. The properties will all be primary properties and so you just have to specify the column for each property in the Column element for each property.
Note that with this pattern, the mapping settings you give to a property in a super class will continue to be correct for the subclasses, so you do not have to shadow the inherited properties in your subclasses.
<ClassMap>
<Name>Person</Name>
<Table>tblPersons</Table>
<InheritsClass></InheritsClass>
<InheritanceType>SingleTableInheritance</InheritanceType>
<TypeColumn>PersonType</TypeColumn>
<TypeValue>P</TypeValue>
...
<PropertyMaps>
<PropertyMap>
<Name>Id</Name>
<IsIdentity>true</IsIdentity>
<Column>PersonId</Column>
...
</PropertyMap>
<PropertyMap>
<Name>FirstName</Name>
<Column>FirstName</Column>
...
</PropertyMap>
<PropertyMap>
<Name>LastName</Name>
<Column>LastName</Column>
...
</PropertyMap>
</PropertyMaps>
</ClassMap>
<ClassMap>
<Name>Employee</Name>
<Table>tblPersons</Table>
<InheritsClass>Person</InheritsClass>
<InheritanceType>SingleTableInheritance</InheritanceType>
<TypeColumn>PersonType</TypeColumn>
<TypeValue>E</TypeValue>
...
<PropertyMaps>
<PropertyMap>
<Name>Salary</Name>
<Column>Salary</Column>
...
</PropertyMap>
<PropertyMap>
<Name>EmploymentDate</Name>
<Column>EmploymentDate</Column>
...
</PropertyMap>
</PropertyMaps>
</ClassMap>
Listing 5 –Person and Employee classes mapped with SingleTableInheritance
The second pattern we will look at is ClassTableInheritance.
Fig 5 – Class Table Inheritance
With this pattern, each class in the hierarchy gets its own table in the database. The tables will only have columns for the non-inherited properties of the class it belongs to.
The root table (the table that the root class in the hierarchy is mapping to, in our example the tblPersons table) will have columns for the identity property or properties in the root class, a type column and of course columns for the properties in the root class.
In the database, the root table column/columns mapped to by the identity property/properties should form a composite primary key together with the type column.
The sub-tables will also have columns for the identity property or properties as well as a type column. Again, they should form a composite primary key for the table, but they should also form a foreign key pointing at the identity column/columns and the type column in the root table.
Note that no matter how many levels down in the hierarchy, the id column/columns and type column of a sub-table should always form a foreign key pointing directly at the corresponding columns in the root table.
This means that the data for an object will be spread out as rows in several tables (except for objects of the root class). In our example, an object of the ValuedCustomer class will be saved as no less than three rows in the database.
As you can imagine, the performance difference between this approach and the SingleTableInheritance approach can become significant. Fetching all the data for a valued customer using this approach requires that data is read from three tables rather than just one as is the case when using SingleTableInheritance.
Nonetheless, there are benefits as well to this approach. You don’t get unused columns in the database and you don’t have to make the columns for properties in your subclasses accept NULL values.
Sometimes more importantly, the number of columns in each table can be kept reasonable for large hierarchies where the total number of properties can have a tendency to add up…
Seeing as there can be reasons to use this pattern sometimes, let’s look at how to map it in our NPersist XML Mapping File.
Perhaps surprisingly, the Employee class in our example will not consider the tblEmployees table as its primary table. Rather, all the classes in the hierarchy will be mapping primarily to the root table (tblPersons) just as if we were using SingleTableInheritance.
This means that, even for a subclass, only the properties found in the root class will be considered primary properties. All the other properties will be non-primary properties, and so in fact the tblEmployees table will be considered a non-primary table for the Employee class, and Salary and EmploymentDate are non-primary properties. nikotinpatronen
Thus, when you write your NPersist XML Mapping File, you must enter the name of the table that each property of a subclass is mapping to. For example, when mapping the Salary and EmploymentDate properties of the Employee class, you’d enter:
<PropertyMap>
<Name>Salary</Name>
<Table>tblEmployees</Table>
<Column>Salary</Column>
...
</PropertyMap>
<PropertyMap>
<Name>EmploymentDate</Name>
<Table>tblEmployees</Table>
<Column> EmploymentDate </Column>
...
</PropertyMap>
Listing 6 – Example of mapping subclass properties using ClassTableInheritance
But that’s not all!
For each non-primary property, you must also specify the foreign key columns relating the non-primary table to the primary table for the class.
We begin by specifying the name of the PersonId column in the IdColumn element. But we have two columns (PersonId and PersonType) in our foreign key. Fortunately, NPersist lets us add any number of additional id columns in the AdditionalIdColumns element.
<PropertyMap>
<Name>Salary</Name>
<Table>tblEmployees</Table>
<Column>Salary</Column>
<IdColumn>PersonId</IdColumn>
<AdditionalIdColumns>
<AdditionalIdColumn>PersonType</AdditionalIdColumn>
</AdditionalIdColumns>
...
</PropertyMap>
<PropertyMap>
<Name>EmploymentDate</Name>
<Table>tblEmployees</Table>
<Column> EmploymentDate </Column>
<IdColumn>PersonId</IdColumn>
<AdditionalIdColumns>
<AdditionalIdColumn>PersonType</AdditionalIdColumn>
</AdditionalIdColumns>
...
</PropertyMap>
Listing 7 – Example of mapping subclass properties using ClassTableInheritance
So, to sum up: When using ClassTableInheritance, all classes in the hierarchy map primarily to the root table and all properties in subclasses are considered non-primary.
Note that as with SingleTableInheritance you do not have to shadow inherited properties.
<ClassMap>
<Name>Person</Name>
<Table>tblPersons</Table>
<InheritsClass></InheritsClass>
<InheritanceType>ClassTableInheritance</InheritanceType>
<TypeColumn>PersonType</TypeColumn>
<TypeValue>P</TypeValue>
...
<PropertyMaps>
<PropertyMap>
<Name>Id</Name>
<IsIdentity>true</IsIdentity>
<Column>PersonId</Column>
...
</PropertyMap>
<PropertyMap>
<Name>FirstName</Name>
<Column>FirstName</Column>
...
</PropertyMap>
<PropertyMap>
<Name>LastName</Name>
<Column>LastName</Column>
...
</PropertyMap>
</PropertyMaps>
</ClassMap>
<ClassMap>
<Name>Employee</Name>
<Table>tblPersons</Table>
<InheritsClass>Person</InheritsClass>
<InheritanceType>ClassTableInheritance</InheritanceType>
<TypeColumn>PersonType</TypeColumn>
<TypeValue>E</TypeValue>
...
<PropertyMaps>
<PropertyMap>
<Name>Salary</Name>
<Table>tblEmployees</Table>
<Column>Salary</Column>
<IdColumn>PersonId</IdColumn>
<AdditionalIdColumns>
<AdditionalIdColumn>PersonType</AdditionalIdColumn>
</AdditionalIdColumns>
...
</PropertyMap>
<PropertyMap>
<Name>EmploymentDate</Name>
<Table>tblEmployees</Table>
<Column> EmploymentDate </Column>
<IdColumn>PersonId</IdColumn>
<AdditionalIdColumns>
<AdditionalIdColumn>PersonType</AdditionalIdColumn>
</AdditionalIdColumns>
...
</PropertyMap>
</PropertyMaps>
</ClassMap>
Listing 8 –Person and Employee classes mapped with ClassTableInheritance
The third – and last – inheritance mapping pattern that we will look at in this document is ConcreteTableInheritance.
Fig 6 – Concrete Table Inheritance
The reason for this name is that only concrete classes are supposed to get a corresponding table in the database, while abstract classes don’t get any tables.
In the case of the NPersist variation on this pattern, the name becomes a bit of a misnomer since here, the root class will always gets a table, abstract or not.
However, abstract classes further down in the hierarchy still don’t need any table in the database, so the pattern name still applies. Furthermore, if the root class is abstract, the root table is only going to need columns for the identity property/properties and the type column, not for any of the other properties.
So, with the ConcreteTableInheritance pattern, each concrete class in the hierarchy gets is own table, in a fashion similar to ClassTableInheritance. As mentioned, the exception is the root class that gets a table regardless of whether it is concrete.
Also as with ClassTableInheritance, the root table will have a composite primary key consisting of the columns for the identity property/properties in the root class, as will the sub-classes where the columns also form a foreign key pointing at the columns in the root table.
The big difference from the ClassTableInheritance pattern is that with ConcreteTableInheritance, each table has columns for all of the properties in the corresponding class – including inherited properties.
This means that the ConcreteTableInheritance pattern represents a trade-off between some of the benefits and drawbacks with the other two patterns.
You don’t have to query three tables to get the data for a valued customer, to begin with. In some O/R Mapping frameworks, you can get away with querying only one table (the tblValuedCustomers table) but NPersist will require an additional call to the root table as well.
Still, you get away with just two calls, regardless of the depth of the hierarchy – except when you load objects of the root class, when you get away with just the one call to the root table.
While this pattern borrows the advantage from the SingleTableInheritance pattern of not having to visit as many tables in the database as there are levels in the hierarchy, it also brings along one of that pattern’s problems, though in a somewhat mitigated form.
With SingleTableInheritance, the root table risks becoming overloaded with columns if there are a large total number of properties in the hierarchy (well, the “root” table is the only table when using SingleTableInheritance).
With ConcreteTableInheritance, it is the sub-tables that risk become overloaded, as they must contain columns for all the properties in the corresponding class. For a class deep down in a hierarchy, that inherits a large number of properties from super classes, this means a large number of columns in the table that the class is mapping to. Портмоне мужское купить Киев
However, the problem is slightly smaller than with SingleTableInheritance since a table only has to hold columns for the properties in the one branch of the hierarchy leading down to it, rather than for all the properties of all the classes in the hierarchy.
Another similarity in issues lies in the NULL value constraints and the unused columns. In this pattern, columns in the root table (except the identity and type columns) will have to allow NULL values and they will go unused when you save objects of subclasses.
These last two issues (NULL values and unused columns) are not always limitations for other implementations of this pattern, but they apply to the NPersist implementation.
Implementing this pattern in the NPersist XML Mapping File is similar to how you implement ClassTableInheritance: All classes in the hierarchy map primarily to the root table and all properties that were not in the root class will be considered non-primary properties.
The difference is that with this pattern you must make use of property shadowing.
Since for example the FirstName properties of the Person class, the Employee class, the Customer class and the ValuedCustomer class map to columns in different tables, we need to override the mapping settings for this property in each class in the NPersist XML Mapping File.
The identity property or properties are the only exception to this rule: they should not be shadowed in subclasses in the XML mapping file. Well, there’s one more exception, which is important but doesn’t come into our example: Collection properties should not be shadowed either.
Note that the shadowing properties, like all other non-primary properties, need to have the information about the foreign key columns pointing back at the primary tables specified.
<ClassMap>
<Name>Person</Name>
<Table>tblPersons</Table>
<InheritsClass></InheritsClass>
<InheritanceType>ConcreteTableInheritance</InheritanceType>
<TypeColumn>PersonType</TypeColumn>
<TypeValue>P</TypeValue>
...
<PropertyMaps>
<PropertyMap>
<Name>Id</Name>
<IsIdentity>true</IsIdentity>
<Column>PersonId</Column>
...
</PropertyMap>
<PropertyMap>
<Name>FirstName</Name>
<Column>FirstName</Column>
...
</PropertyMap>
<PropertyMap>
<Name>LastName</Name>
<Column>LastName</Column>
...
</PropertyMap>
</PropertyMaps>
</ClassMap>
<ClassMap>
<Name>Employee</Name>
<Table>tblPersons</Table>
<InheritsClass>Person</InheritsClass>
<InheritanceType>ConcreteTableInheritance</InheritanceType>
<TypeColumn>PersonType</TypeColumn>
<TypeValue>E</TypeValue>
...
<PropertyMaps>
<PropertyMap>
<Name>FirstName</Name>
<Table>tblEmployees</Table>
<Column>FirstName</Column>
<IdColumn>PersonId</IdColumn>
<AdditionalIdColumns>
<AdditionalIdColumn>PersonType</AdditionalIdColumn>
</AdditionalIdColumns>
...
</PropertyMap>
<PropertyMap>
<Name>LastName</Name>
<Table>tblEmployees</Table>
<Column>LastName</Column>
<IdColumn>PersonId</IdColumn>
<AdditionalIdColumns>
<AdditionalIdColumn>PersonType</AdditionalIdColumn>
</AdditionalIdColumns>
...
</PropertyMap>
<PropertyMap>
<Name>Salary</Name>
<Table>tblEmployees</Table>
<Column>Salary</Column>
<IdColumn>PersonId</IdColumn>
<AdditionalIdColumns>
<AdditionalIdColumn>PersonType</AdditionalIdColumn>
</AdditionalIdColumns>
...
</PropertyMap>
<PropertyMap>
<Name>EmploymentDate</Name>
<Table>tblEmployees</Table>
<Column> EmploymentDate </Column>
<IdColumn>PersonId</IdColumn>
<AdditionalIdColumns>
<AdditionalIdColumn>PersonType</AdditionalIdColumn>
</AdditionalIdColumns>
...
</PropertyMap>
</PropertyMaps>
</ClassMap>
Listing 9 – Person and Employee classes mapped with ConcreteTableInheritance
Now that we know how to implement the three different supported inheritance patterns, the time has come to return to the case of polymorphic relationships.
Take the example from Fig 2 with a Dog class containing a BelongsTo property for holding a reference to an object of the Person class or any of its subclasses. Let’s begin by considering how we could implement this using SingleTableInheritance.
We already know what the table for our Person class hierarchy will look like using this pattern (see Fig 4) but how should the tblDogs table for our Dog class look?
First of all, we need a column for the Name property of the dog class, and since the Name property is the Identity property for the Dog class, the corresponding Name column should be made the primary key for the table.
Then we need a column for the Color property, and finally of course we need a column for the BelongsTo reference property.
This column should point at the PersonId column in the tblPersons table. But of course we would like to use a foreign key relationship here, and a foreign key must contain columns for all the columns in the primary key it is pointing at.
The primary key in the tblPersons table contains of two columns – PersonId and PersonType – and that means our foreign key will have to use two columns as well. Thus, we get the table depicted in Fig 7.
Fig 7 – Polymorphic Relationship Implementation
In order to implement this reference property in the NPersist XML Mapping File, you’ll have to use the AdditionalColumns element, since more than one column is used in order to hold the relationship.
<PropertyMap>
<Name>BelongsTo</Name>
<DataType>Person</DataType>
<ReferenceType>OneMany</ReferenceType>
<Column>BelongsTo_PersonId</Column>
<AdditionalColumns>
<AdditionalColumn>BelongsTo_PersonType</AdditionalColumn>
</AdditionalColumns>
...
</PropertyMap>
Listing 10 – Example of mapping polymorphic reference property
With SingleTableInheritance, it’s easy to see how this will “just work”.
Since any object in the class hierarchy can (and will) be saved as a row in the same table then of course our reference property will be able to hold references to object of any class in the hierarchy, and it will only have to look in one table to know it will be able to find the row for the referenced object.
Now, the nice thing about the NPersist variation on the ClassTableInheritance and ConcreteTableInheritance patterns – which is to always have a concrete root table that all classes in the hierarchy are mapping to primarily – is that polymorphic relationships will “just work” for these two patterns too.
The tblDogs table in Fig 7 will look the same regardless of which of the three patterns we’re using to implement our Person class hierarchy – always using the same foreign key pointing at the root table. The XML for the reference property in the NPersist XML Mapping File will also look the same regardless of the pattern used.
Even if we decide that the BelongsTo property should only be able to take Customer and ValuedCustomer objects by changing the data type for the property to Customer, the tblDogs table and the XML for the property will remain the same (except that the DataType element should be updated).
A closer discussion on why polymorphic relationships “just work” with the NPersist variations on the ClassTableInheritance and ConcreteTableInheritance patterns will be saved for another time.
For now, it is enough to know how you implement them and that you don’t have to pay any attention to which pattern that is being used for mapping your inheritance hierarchies.
Polymorphic relationships work with all combinations of inheritance pattern and relationship types (OneMany/ManyOne, ManyMany and OneOne) and for bi-directional as well as unidirectional relationships.
Also note that the Dog class could also be involved in a class inheritance hierarchy of its own (perhaps inheriting from Animal and with the subclass Dalmatian). Either or both of the classes in a polymorphic relationship can be part of a class hierarchy – the polymorphic relationships will continue to “just work”.
This document has showed you how to map class inheritance hierarchies in your persistent object models to one or several database tables using any of the three major inheritance patterns, SingleTableInheritance, ClassTableInheritance and ConcreteTableInheritance.
You have also learned how to implement polymorphic relationships and seen that they “just work” regardless of the pattern you chose for your hierarchies.
Furthermore, you have learned about how to use non-primary properties, which has uses outside of mapping inheritance hierarchies.
In summary, you now know all you need to in order to map your class hierarchies to the database using the MatsSoft NPersist framework.
Good luck and Happy Hacking!
/Mats