NConstruct - Intelligent Software Factory

Inheritance – Table Per Subclass Hierarchy Author: Sebastijan Pistotnik, member of NConstruct Developers Team
Release date: February, 2008


Inheritance – Table Per Subclass Hierarchy

This article discusses:

  • Problems in coding an OR mapping by not using polymorphism
  • Using polymorphic associations and polymorphic queries
  • Creating Table Per Subclass Hierarchy in NConstruct application builder
Contents:
Let us assume a task of writing a business application that handles purchase and sales orders for a fictitious bicycle manufacturer. DB architect designs a database similar to the Adventure Works database that can be found and downloaded on the following URL:

http://www.codeplex.com/MSFTDBProdSamples/Release/ProjectReleases.aspx?ReleaseId=8392

We will keep our focus only on three of the tables named SalesOrderDetails, PurchaseOrderDetails and Product. The database tables look like ones in the Figure 1.

Note

Adventure Works is a sample database. Table names, their relationships and other properties are fictitious and not something that someone would actually design in that way.

Figure 1



We will use an NConstruct builder and create a default mapping based on Table Per Concrete Class strategy. The builder creates a separate entity class for every existing table.

We start coding and with time our number of lines of code is getting larger and larger. We start wondering how to improve our coding. Let us look at this concrete class mapping and see what kind of problems we have.

1 Problems in coding when using type – based alternatives

We have a method for closing an order. We somehow manage to simplify the code to the following state:



As you can see, we have two methods, since we have two concrete entity classes mapped to two separate tables and each of them has a separate call to CloseOrder method. Could we get rid of this second method?
A quick look at the above code would give a programmer a quick solution. Why not design this using if-then-else or case statement conditional logic.
The problem transforms into “How to handle type-based alternatives”?



Conditional variation is a fundamental theme in programs. If a program is designed using if-then-else or case statement conditional logic, then if a new variation arises, it requires modification of the case logic - often in many places . This approach makes it difficult to easily extend a program with new variations because changes tend to be required in several places - wherever the conditional logic exists.

Solution
When related alternatives or behaviors vary by type (class), assign responsibility for the behavior using polymorphic operations to the types for which the behavior varies.
Do not test for the type of an object and use conditional logic to perform varying alternatives based on types.
We will introduce details (and code solution) to the implementation later in the article.

2 Problems in coding when not using polymorphic queries

The problems are appearing not only in methods, but also in query calls:



We could rather have just one method and one query :



Or let us look at a more “polymorphically” oriented example: Since the two tables both refer to the same Product table, we could have:



In this case we would also like to have just one simple method call and process orders polymorphically:



There are also other kinds of problems that appear. We introduced just a few of them.

3 Possible Solution – Table Per Subclass Hiearchy

Now back to our database example. As you can see, those two tables have a lot of common columns declared. So they are in a way duplicated, which is definitely something that we should avoid. There are many approaches possible. We will take the approach of joining those two tables into a single one called Orders. What we need is the entire hierarchy to be mapped into a single table. We have to add a special column to distinguish between persistent classes: the discriminator. This is not a property of the persistent class; it is used internally by NHibernate.
The column name will be OrderType, and domain values will be strings - in this case, “SALES” and “PURCHASE”. NHibernate automatically sets and retrieves the discriminator values. So the concrete subclass represented by a particular row is identified by this value.

Let’s see how our SQL database script for creating an Orders table looks like:

Note
We are going to simplify things a bit, not to create “all” or “same as existed in Adventure Works database” many-to-one references.



There is one major problem: Columns for properties declared by subclasses must be declared to be nullable. Since our subclasses each does not define several non-nullable properties, the loss of NOT NULL constraints may not be a serious problem from the point of view of data integrity . Another important issue is normalization. We have created functional dependencies between nonkey columns (Note: a nonkey is a field that does not serve as a candidate, primary, alternate, or foreign key. Its sole purpose is to represent a characteristic of the table's subject, and its value is determined by the primary key), violating the third normal form. Details can be found on the following URL:

http://en.wikipedia.org/wiki/Third_normal_form

When subclasses declare relatively few properties (particularly if the main difference between subclasses is in their behavior), then violation might not be a problem. Your goal is to minimize the number of nullable columns and to convince your DBA that a denormalized schema will not create problems in long term stability, maintainability, and the integrity of data. Note that the performance may also be achieved by proper optimization of the SQL execution plans.

3.1.1 Solution to problem 1 – Polymorphic association

What we need is a so called polymorphic association. After mapping modified tables, we have a ProductsEntity entity class that has an association to an OrdersEntity entity class.

Note
This is a simplification though. Because if you carefully look at the table SalesOrderDetails in AdventureWorks database you can see that it has a reference to a table SpecialOfferProduct with a composed primary key.

This is a polymorphic association. At runtime, a product may reference an instance of any of the subclass of OrderEntity. A polymorphic association is an association that may refer instances of subclass of the class that was explicitly specified in the mapping metadata. Now let’s suppose that a ProductEntity entity class would be mapped as having a one-to-many association to OrdersEntity entity class.
We may iterate over the collection and handle instances of SalesOrdersEntity and PurchaseOrdersEntity polymorphically:



One of the common ways to apply polymorphism is in the context of what Peter Coad calls the “Do It Myself” strategy or pattern (Coad, OO 1995. Object Models: Strategies, Patterns and Applications.):
“I (a software object) do those things that are normally done to the actual object that I am an abstraction of.”

This is a classic object-oriented design style: Circle objects draw themselves, Square objects draw themselves, Text objects spell-check themselves, and so forth. Notice, that Circle and Square objects drawing themselves are examples of polymorphism:
“When related alternatives vary by type, assign responsibility using polymorphic operations to the types for which the behavior varies.”
Do It Myself and Polymorphism usually lead to the same choice.

3.1.2 Solution to Problem 2 - Polymorphic queries

We want to be able to write polymorphic queries (queries that return objects of all classes that match the interface of the queried class) that refer to the Order class, and have the query returns instances of its subclasses. We can achieve this with an object oriented query language HQL:



This query returns objects of type OrdersEntity, which is an abstract class. In this case, the concrete objects are of the subtypes of OrdersEntity: PurchaseOrdersEntity and SalesOrdersEntity.

If only instances of a particular subclass are required, you may use: 



We can also use a more complicated fetch: Suppose a many-to-one association named highestOrder exist between ProductsEntity and OrdersEntity



This mapping strategy is a winner in terms of both performance and simplicity.
  • It is the best-performing way to represent polymorphism - both polymorphic and nonpolymorphic queries perform well.
  • Ad-hoc reporting is possible without complex joins and unions.
  • There is only one insert for each entity in case of saving many of them, so scalability is not compromised.
  • Schema evolution is straightforward.

4 How to implement Table Per Subclass with NConstruct builder

The implementation is possible in the Objects management step of a wizard. We select an OrdersEntity class and click on Inheritance and it’s Table Per Class hierarchy toolbar subitem shown in Figure 2.

Figure 2



The following wizard, shown in Figure 3, opens.

Figure 3



4.1 Implementation with discriminator column

We unselect ModifiedDate, OrderQty, Product, UnitPrice from nullable candidate properties list. That way we move those properties that actually belong to both of subclass entities into an abstract parent class. We select a discriminator column and enter 2 for a number of subclasses to create. We get a situation as in the following Figure 4.

Figure 4



After clicking the Next button , we get the screen presented in Figure 5.

Figure 5



We enter appropriate values for class names and discriminator values and select ReceivedQty and RejectedQty in PurchaseOrdersEntity properties list, which we think they belong to.

Note
ReceivedQty probably makes no sense in sales business context.

The entered values can be seen in Figure 6.

Figure 6



After clicking Next and Finish buttons, subclasses and their abstract base class should be successfully created. After running the target application, the created two entities have their two corresponding navigation items named by default as Sales Orders Subclass and Purchase Orders Subclass (Figure 7).

Figure 7



A report query SQL that NHibernate executes to get purchase orders records is as follows: 


 
However, the point here is that we can now create an abstract CloseOrder method and implement concrete implementation in individual concrete subclasses.



The generated class hierarchy introduced as UML is shown in Figure 8.

Figure 8



4.2 Implementation with the formula SQL expression

Sometimes , especially in legacy schemas, we do not have a freedom to include an extra discriminator column in our entity table. In this case, we can apply a formula to calculate a discriminator value for each row (Figure 9).

formula = "case when ReceivedQty IS NULL then 'SALES' else 'PURCHASE' end"

Note
We are simplifying and assuming here things a bit, just to introduce an example.

Figure 9



The screen for entering the values of subclasses looks the same as the above in Figure 6.

This mapping relies on SQL CASE/WHEN expression to determine whether a particular row represents a sales or a purchase order. The result of the expression is a literal, SALES or PURCHASE, which in turn is declared on the mappings like this:



At the end, only the SQL gets a little different than before, but the results are the same.

Note
We do not need an additional OrderType column.

In case of executing a query on top of a PurchaseOrdersDTO, we get the SQL as follows:



Tip
The same as the above example could be achieved with entering:

Formula=”case when OrderType = 'SALES' then 'SALES' else 'PURCHASE' end”

Return type in this example must be String and “SALES” and “PURCHASE” must be entered for discriminator values.