Inheritance in the Entity Framework

Published 15 March 07 09:00 AM | dpblogs 

 

One of the coolest features of the ADO.NET Entity Framework is the ability to use inheritance in your database! Very cool, but what does it mean, and why is it important?

 

War of the worlds

 

Relational

The world of relational data is based around tuples, which have an inherent two dimensional structure. Think of a database table with rows and columns; it is a very two dimensional idea. Relationships, UDTs, views, etc are all extensions of this two dimensional view. This structure allows for the power we know and love in products like SQL Server, with features like query optimization, indexes, views, etc.

 

Objects

Object oriented programming (OOP) drives higher developer productivity and allows for applications to better represent the world in which they operate. One of the ways that they do this is by utilizing inheritance. Inheritance allows for an application to better model the data, and also provides the ability to extend an existing model and application in interesting ways.

 

Union of worlds

While the relational model has a lot of power, its way of looking at the world is somewhat at odds with the gestalt of object oriented programming.

 

The Entity Framework helps bridge these worlds by bringing the power of inheritance to the world of data access in ways that make sense and allow for the best features of both to shine through. To illustrate this, we will look at some of the benefits of OOP, and see how the Entity Framework helps bring these benefits to the store.

 

Why OOP?

 

Problem Modeling

In OOP, inheritance is often used to represent objects that have a IS-A relationship. This simply means that one object is a specialization of the other. For example, think of an online store with Products. A Product has certain attributes and data associated with it. Now, there is also a Discontinued Product which has all the same data as a regular Product, but also something more, namely a discontinued date.  You could create a new object to represent the Discontinued Product, but it makes a lot more sense to create a new object that inherits from Product, and adds the additional field. After all, programmers are lazy, and why would I want to write more code then I need to!

 

Application Extension

You’ve done such a great job, and this online store has such a great database and application driving it, it’s ready to expand into new markets. The store is ready to branch out into seasonal products!

 

This scenario really shows off the extension power of OOP. You simply need to write a new object that inherits from Product and applies some different logic in its methods. For example, you might only show summer products in the summer or automatically provide a 10% discount for summer products in the fall. And all of the existing systems to manage inventory, shopping carts, etc just continue to work, as everything is still made up of Products!

 

How the Entity Framework bridges the gap

 

The ideas presented above are fairly basic; generally introduced in OOP 101. So what is the big deal? Let’s look at how we apply these scenarios in the Entity Framework, so we can see how powerful it is. This will also give us an opportunity to dive into the specifics of how the translation of OOP ideas to the relational world works.

 

To make the scenario specific, let’s use the example of an online hardware store, with both Discontinued Products, and Seasonal Products. The Entity Data Model (CSDL) for the Products might look something like the following.

 

<EntityType Name="Product" Key="ProductID">

  <Property Name="ProductID" Type="Int32" Nullable="false" />

  <Property Name="Name" Type="String" MaxLength="500" Nullable="false"/>

  <Property Name="Price" Type="Decimal" Nullable="false" />

</EntityType>

 

<EntityType Name="DiscontinuedProduct" BaseType="Product">

  <Property Name="DiscontinuedDate" Type="DateTime" Nullable="false"/>

</EntityType>

 

<EntityType Name="SeasonalProduct" BaseType="Product">

  <Property Name="OffSeasonDiscount" Type="Float" Nullable="false"/>

</EntityType>

 

The CLR code for this situation is not shown, but we would have the same inheritance hierarchy in the generated CLR classes, with the full capabilities that this implies. The interesting thing with respect to this post is the OO to relational mapping.

 

Table per Hierarchy

Let’s start with the Discontinued Product, and see how you might model this in a database. You know that you will need to maintain a list of discontinued products (to maintain referential integrity), so you might create a table that contains all products with data like the following.

 

ProductID

Name

Price

Discontinued

Discontinued Date

1

Nail

$1.40

No

Null

2

Bubble level

$5.50

Yes

2/2/07

 

How do you use inheritance with data like this? Looking at the data, you know that when the Discontinued field is true, we’re dealing with a discontinued product. This is exactly the way that Table per Hierarchy (TPH) works! The idea is that the entire OO hierarchy is contained in one table, with some column(s) acting as discriminator. The value of the discriminator is what informs the Entity Framework what OO type each row contains.

 

For this setup, the mapping file might look something like the following. The Condition tag identifies the discriminator for the type.

 

<EntityTypeMapping TypeName="Product">

  <TableMappingFragment TableName="Products">

    <ScalarProperty Name="ProductID" ColumnName="ProductID" />

    <ScalarProperty Name="Name" ColumnName="Name" />

    <ScalarProperty Name="Price" ColumnName="Price" />

    <Condition ColumnName="Discontinued" Value="0"/>

  </TableMappingFragment>

</EntityTypeMapping>

 

<EntityTypeMapping TypeName="DiscontinuedProduct">

  <TableMappingFragment TableName="Products">

    <ScalarProperty Name="ProductID" ColumnName="ProductID" />

    <ScalarProperty Name="Name" ColumnName="Name" />

    <ScalarProperty Name="Price" ColumnName="Price" />

    <ScalarProperty Name="DiscontinuedDate" ColumnName="DiscontinuedDate" />

    <Condition ColumnName="Discontinued" Value="1"/>

  </TableMappingFragment>

</EntityTypeMapping>

 

 

Table per Type

Perhaps we did not initially intend to sell Seasonal Products, so they were not introduced until after the application was deployed. Modifying a core table of a live application is a good way to get the adrenaline flowing, and risk that new boat you have been saving for. We do not want to modify the Products table to add any new information!

 

We can create a new table with the Seasonal Product information, and create a one-to-one relationship between the two. Then, we simply need to modify the mapping file to let the Entity Framework know that the additional information associated with Seasonal Products can be found in another table. This is the core of Table per Type (TPT), where each table represents a type, but with only those fields associated with that type in the table. The mapping for this situation might look like the following.

 

<EntityTypeMapping TypeName="SeasonalProduct">

  <TableMappingFragment TableName="Products">

    <ScalarProperty Name="ProductID" ColumnName="ProductID" />

    <ScalarProperty Name="Name" ColumnName="Name" />

    <ScalarProperty Name="Price" ColumnName="Price" />

  </TableMappingFragment>

  <TableMappingFragment TableName="SeasonalProducts">

    <ScalarProperty Name="ProductID" ColumnName="ProductID" />

    <ScalarProperty Name="OffSeasonDiscount" ColumnName="OffSeasonDiscount" />

  </TableMappingFragment>

</EntityTypeMapping>

 

 

Table per Concrete Type

We are going to have a long and successful run; our store is going to grow and prosper. The housing boom continues and we have millions of users. Competitors are entering the market, and so we want to make sure we do not have issues with scaling. One issue is that the number of products will increase and decrease over time, but it won’t change by a huge amount. However, the number of discontinued products is only going to increase with time.

 

To deal with this, we might want to move all the discontinued products to their own Discontinued Product table, perhaps on a linked server or on another filegroup. However, we don’t want to change the application to make this change. With the Entity Framework we don’t need to!

 

The Discontinued Product table contains all fields that exist on Discontinued Products, not just those that do not apply to  other products (as was the case with TPT). This is the essence of Table per Concrete Type (TPC). Each table represents the entire Entity, and so when they are loaded, you only need to load from that one table. The mapping for TPC might look something like the following.

 

<EntityTypeMapping TypeName="DiscontinuedProduct">

  <TableMappingFragment TableName="DiscontinuedProducts">

    <ScalarProperty Name="ProductID" ColumnName="ProductID" />

    <ScalarProperty Name="Name" ColumnName="Name" />

    <ScalarProperty Name="Price" ColumnName="Price" />

    <ScalarProperty Name="DiscontinuedDate" ColumnName="DiscontinuedDate" />

  </TableMappingFragment>

</EntityTypeMapping>

 

Wrapping up…

 

As you can see from all this, the Entity Framework’s separation of the model from the database allows for some very cool scenarios to work. By using the different inheritance models supported, you can have the best of both the relational and the OO worlds. Viva la difference!

 

Please leave a comment with any questions that you have, or if you’d like to see more detail on any of the technologies mentioned.

 

Thanks,

Erick Thompson

ADO.NET Program Manager

 

Filed under:

Comment Notification

If you would like to receive an email when updates are made to this post, please register here

Subscribe to this post's comments using RSS

Comments

# jvierra said on March 15, 2007 7:44 PM:

One thing I can see when looking at the blog source is that there is a fair amount of bloat due to teh MSOffice formatting.

I wonder if, under some circumstances, this may cause slow rendering performance?

I mention this because, on many sites, IE7 tends to build it's page very slowly.  Not this on for me but it does happen.  The same site on IE6 render norrmally.

Is it machine settings or IE7 issues with some layouts?

# ArchitectualInsight said on March 16, 2007 3:31 PM:

I was/am so busy in two projects , there was no time for any blah blah and blogging.. I still don't have

# Giancarlo Sudano said on March 16, 2007 6:56 PM:

how do you manage polimorphic query with inheritance?

In NHibernate if I use a TPC strategy, and I create a query "from BaseClass" I usually obtain a SELECT with UNION from all several table per concrete.

Normally for a polimorphic query a TPH or a Table per Subclass strategy (S.Ambler definition) is better.

Do Entity Framework manages polimorphic query?

Thanks!

# Steve said on March 17, 2007 9:29 AM:

First things first, how about adding 1:1 support  :)

Isn't that missing from this CTP?

By the way, I'd like to have the EF use an NHibernate approach where mapping files are used as above, without cluttering the entity/value objects.

# Sam Gentile said on March 17, 2007 10:03 PM:

Yup, I'm still stuck in Seattle and I still feel like crap. Tomas just went off to the airport and I

# Erick Thompson said on March 18, 2007 2:24 PM:

re: Do Entity Framework manages polimorphic query?

Entity Framework queries can indeed handle polymorphic queries, in that you can query for a base type, derived type, etc.

re: By the way, I'd like to have the EF use an NHibernate approach where mapping files are used as above, without cluttering the entity/value objects.

With the Entity Framework, the mapping files all live on thier own, so there is no merging of mapping, store and objects. In additon, with a forthcoming release of the Entity Framework, we will be supporting the ability to use your own objects (not using our code gen) with the EF.

# Arjen de Blok said on March 21, 2007 8:25 AM:

I would also like that to use the POCO style from NHibernate with the Entity Framework.

Thus that the entity classes have no dependency on the entity framework. So no specific base classes where you must derive from or .NET attributes.

Implementing interfaces like INotifyPropertyChanged is no problem for me.

# Steve.Walker@gmail.com said on March 22, 2007 1:05 AM:

How might one implement the entity framework from an ETL standpoint? Is that a valid idea at all?  e.g. pre-ado.net data access layer...

# Steve.S.Walker@gmail.com said on March 22, 2007 1:05 AM:

How might one implement the entity framework from an ETL standpoint? Is that a valid idea at all?  e.g. pre-ado.net data access layer...

# Console.Write(this.Opinion) said on March 26, 2007 11:36 AM:

Esta semana não foi tão animada quanto a semana passada.. ASP.Net Sébastien Just fez uma compilação das

# WeLikeIke said on April 2, 2007 12:19 PM:

I can't seem to get an Association/AssociationSet End Role in a .csdl file to work if the End Role type is derived from the EntitySet type.  Is that even a possible scenario?  

The other part of that problem is that apparantly in the .msl file, I must include the mappings for all types derived from a base object within the base object's EntitySetMapping node.  Otherwise I get an error stating that a particular TableMappingFragment is basically defined twice and could lead to data corruption.

In other words, using the example .csdl at...

http://blogs.msdn.com/adonet/archive/2007/02/12/entity-data-model-101-part-2.aspx

...how would you change the type of the End Role "ManagedEmployee" in Association "FK_Employee_Employee_ManagerID" from "Employee" to "SalesEmployee"?

Thanks...

# WeLikeIke said on April 2, 2007 1:47 PM:

Uhh..I think I found the answer which stinks if true.  

Again, from http://blogs.msdn.com/adonet/archive/2007/02/12/entity-data-model-101-part-2.aspx ...

"Any associations using a derived type must be declared on the base type because the derived type does not declare an entity set in the entity container. The entity set is needed to define the scope of an association using the derived type."

Please say it ain't so.  To me, that seems like a severe limitation.

# WeLikeIke said on April 2, 2007 2:03 PM:

Found more regarding derived type associations (relationships).  

I guess that functionality is being considered:

http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=967167&SiteID=1

Sure would be nice if it gets included...

# Paymon Khamooshi said on March 2, 2008 4:33 AM:

It will be great to add a standard Parse() method to the database context's table properties to accept the ToString() value of an instance and do the query based on the configurations.

Currently the developer needs to know which field to search for, i.e:

dbContext.Publishers.Single(p => p.Name == "Wrox")

this can be simplified as

dbContext.Publishers.Parse("Wrox")

# Dating said on May 31, 2008 2:28 PM:

One of the coolest features of the ADO.NET Entity Framework is the ability to use inheritance in your database! Very cool, but what does it mean, and why is it important? War of the worlds Relational The world of relational data is based around tuples

# Weddings said on June 5, 2008 6:20 AM:

One of the coolest features of the ADO.NET Entity Framework is the ability to use inheritance in your database! Very cool, but what does it mean, and why is it important? War of the worlds Relational The world of relational data is based around tuples

# Fakher Halim said on July 15, 2008 10:28 AM:

A working example of Table per Hierarchy for Visual Studio 2008 SP1 is available at

http://www.codeproject.com/KB/architecture/LinqEntityFramework.aspx

# Hitesh said on September 4, 2008 7:02 AM:

Hi There,

Good article on explanation of inheritance in entity framework..

I have a perticular sutuation where by , I have to inherit from a given entity solely for the purpose of adding more calculated fields .. and however DO NOT SAVE the inherited entity to database...

for .e.g.

I have an entity

"Contractor" which contains.. "HourlyRate" and "EstimatedHours"

and is working fine for saving these two values using entity framework...

However, I now NEED TO DEFINE an INHERITED entity for reporting purpose..

"EstimatedCotractorCost" which will inherit from "Contractor" entity and will have a field "EstimatedCost" which should be "HourlyRate * EstimatedHours" ...and should not be serialised.

how can i do that?

Your help would be much appriciated.

Hitesh.

# Ricardo said on October 8, 2008 2:02 PM:

How could I change the type of an object since the condition, ProductType, is not mapped to a property? For instance: I would like to save a RegularProduct as a DiscontinuedProduct. It´s is possible?

I´d appreciate if someone could answer this question.

Thanks,

Ricardo

# Sam Gentile's Blog said on December 3, 2008 10:01 AM:

Yup, I'm still stuck in Seattle and I still feel like crap. Tomas just went off to the airport and I feel like the last MVP left in Seattle. Just want to get out of here and home but can't do that until tomorrow night. Lots of stuff stored up Entity Framework/ADO.NET

# Greg said on December 13, 2008 1:25 PM:

I'm not finding a full example of how to model Table Per Concrete Type anywhere. I suppose the basic dilemma is how one models the column mappings of the properties in the abstract base type that one defines in the conceptual model, since any given one of those properties will be sourced from multiple tables.

# Community Blogs said on May 15, 2009 7:09 AM:

SharePoint Create your own customized usage report solution step by step SharePoint WebPart Property

Leave a Comment

(required) 
(optional)
(required) 
Page view tracker