EF6 Code First: Configuring Unmapped Base Types

If your object model contains inheritance, Code First gives you two options for the base type – it can either be mapped or unmapped.

A mapped base type means the inheritance hierarchy is represented in the database using either the TPH, TPT or TPC pattern. An unmapped base type means Code First effectively ignores your base type and acts as if the properties defined in the base type were defined on each derived type.

Note: The code in this post is written using EF6 Alpha 2, if you are using a later release you may need to adjust the code to reflect API changes.

Prior to EF6

Prior to EF6 there was no way to configure an unmapped base type. If you wanted to configure a property defined on an unmapped base type you had to explicitly configure it on every derived type.

For example, in the following model we want all types that inherit from EntityBase to use Key as their primary key and to configure ConcurrencyToken as a Rowversion/Timestamp column.

public class EntityBase
{
  public int Key { get; set; }
  public byte[] ConcurrencyToken { get; set; }
}

public class Blog : EntityBase
{
  public string Name { get; set; }
  public string Url { get; set; }

  public List<Post> Posts { get; set; }
}

public class Post : EntityBase
{
  public string Title { get; set; }
  public string Content { get; set; }

  public int BlogId { get; set; }
  public Blog Blog { get; set; }
}

If we were to configure EntityBase using the fluent API then it would be included in the model and Blog and Post would share a table in the database. The only alternative we are left with is to configure the properties for every type that derives from EntityBase.

public class MyContext : DbContext
{
  public DbSet<Blog> Blogs { get; set; }
  public DbSet<Post> Posts { get; set; }

  protected override void OnModelCreating(DbModelBuilder modelBuilder)
  {
    modelBuilder.Entity<Blog>().HasKey(b => b.Key);
    modelBuilder.Entity<Blog>().Property(b => b.ConcurrencyToken).IsRowVersion();

    modelBuilder.Entity<Post>().HasKey(p => p.Key);
    modelBuilder.Entity<Post>().Property(p => p.ConcurrencyToken).IsRowVersion();
  }
}

This is an annoying violation of the DRY (Don’t Repeat Yourself) principle… fortunately EF6 comes heralding good news.

EF6 to the Rescue

EF6 introduces the Custom Code First Conventions feature – personally it’s my favorite new feature. I can define a convention that performs a set of configuration for every entity that derives from EntityBase in my model.

modelBuilder.Types<EntityBase>().Configure(c =>
  {
    c.HasKey(e => e.Key);
    c.Property(e => e.ConcurrencyToken).IsRowVersion();
  });

I’ve written this convention using ‘lightweight conventions’, this part of the custom conventions feature allows you to build conventions using an API surface that looks and feels similar to the Code First Fluent API. For more information the different types of conventions you can write, check out the walkthrough and feature specification.