Entity Framework and Concrete-Table-per-Type Inheritance


As I alluded to on a recent post of mine, I’ve been experimenting with inheritance in EF4. EF4 (allegedly) supports 3 types: –

  • Table-per-Hierarchy: One physical DB table contains all fields for the entire type hierarchy. This is the only mode of inheritance in Linq to SQL.
  • Table-per-Type: One physical DB table stores all shared fields, whilst each type has its own table for type-specific fields.
  • Table-per-Concrete Type: Each type has its own physical DB table, even for common (base types) field.

Now, the first two are well documented on MSDN but the third is conspicuously absent. It turns out that there is no design-time support for this model, nor is there any real documentation on how to do it! I’ve surfed around and not really found much in the way of helpful guidance on this, so here’s my take on it.

Here’s a (very) simple set of database tables:

Inherit1

Let’s now push that into EF4 using the designer:

Inherit2

Oh look! There are two common fields. Let’s make a nice type hierarchy out of them, by creating a new abstract entity called Employee and then tying them all together (and removing the common fields from the two concrete entities):

Inherit3

Hit compile and…. it doesn’t work. The first problem you’ll get is that you need to map the Id and Name properties from the base Employee entity to both physical tables. How do we do that? Well, you can try to go to mapping of Employee in the designer and doing the following:

image

It won’t work. You still need to map the unique identifier column (ID) to both the Developer and Manager entities – but you can’t do this in the designer.

So you open up the model in the XML Editor (Open with…) and you get a whole load of XML.

  • SSDL: The database defintions; you won’t need to modify this.
  • CSDL: The conceptual model i.e. the entities you see in the designer. You won’t need to modify this.
  • CS Mapping: The mapping between the above two models.
  • Designer content: Ignore this; it contains the designer surface details e.g. where on the screen the entities should be displayed etc.

    So, you go into the CS Mapping section, and create a new scalar property in both Manager and Developer mapping fragments for ID e.g.

            <EntityContainerMapping StorageEntityContainer="TestModelStoreContainer" CdmEntityContainer="TestEntities">
              <EntitySetMapping Name="Employees">
                <EntityTypeMapping TypeName="IsTypeOf(TestModel.Developer)">
                  <MappingFragment StoreEntitySet="Developer">
                    <ScalarProperty Name="Skill" ColumnName="Skill" />
                    <ScalarProperty Name="Age" ColumnName="Age" />
                  </MappingFragment>
                </EntityTypeMapping>

    becomes

            <EntityContainerMapping StorageEntityContainer="TestModelStoreContainer" CdmEntityContainer="TestEntities">
              <EntitySetMapping Name="Employees">
                <EntityTypeMapping TypeName="IsTypeOf(TestModel.Developer)">
                  <MappingFragment StoreEntitySet="Developer">
                    <ScalarProperty Name="Id" ColumnName="Id" />
                    <ScalarProperty Name="Skill" ColumnName="Skill" />
                    <ScalarProperty Name="Age" ColumnName="Age" />
                  </MappingFragment>
                </EntityTypeMapping>
    OK, let’s try to compile again. Still no luck – VS now complains about the lack of the mapping for the Name property, too! In other words:

you need to manually map across all shared properties from the base class to all derived classes

Once you create another mapping for Name (just like I did for ID), your code will compile, and you can do code like the following: –

var context = new TestEntities();
context.AddToEmployees(new Manager());
context.AddToEmployees(new Developer());
context.SaveChanges();

 

You can also query the Employees collection on the context in order to get all Employees, or do a Employees.OfType<Developer>().

Advertisements

6 thoughts on “Entity Framework and Concrete-Table-per-Type Inheritance

  1. I tried to follow this example, but I cant not get to work. I am getting error 3032… Mapping Conditions can be used to distinguish the rows….

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s