Code First Migrations History Table Customization

The migrations history table is an Entity Framework system table used to store metadata describing the schema version history of one or more EF Code First models within a given database.

History table customization is a new feature allowing various aspects of the history table (such as table name, column facets etc.) to be configured. It is an advanced feature primarily intended to improve the Migrations experience with third-party providers (where the default history model configuration is not always ideal). Care needs to be taken when customizing the history model as it becomes possible to define a model that no longer properly supports the migrations runtime – EF does not currently check whether a customized history model is compatible with the runtime. Additionally, customization must happen before the first migration is applied and is not supported if the first migration is an auto-migration. Migrations will detect any changes to the history model subsequent to the initial code migration and throw an appropriate error.

Configuration is expressed in a way already familiar to Code First users: Deriving a “history” DbContext, overriding OnModelCreating and calling fluent APIs on the provided DbModelBuilder instance.

1.     Deriving a History Context

The first step in customizing the history table is to subclass System.Data.Entity.Migrations.History.HistoryContext – this is the special derived DbContext class that Migrations uses internally to interact with the history table:

public class MyHistoryContext : HistoryContext
    public MyHistoryContext(
        DbConnection existingConnection, 
bool contextOwnsConnection,
string defaultSchema) : base(existingConnection, contextOwnsConnection, defaultSchema) { } }

2.     Override OnModelCreating

Next, we can override OnModelCreating in the normal way in order to configure the history model:

protected override void OnModelCreating(DbModelBuilder modelBuilder)
.Property(h => h.MigrationId).HasColumnName("migration_id"); modelBuilder.Entity<HistoryRow>()
.Property(h => h.ContextKey).HasColumnName("context_key"); modelBuilder.Entity<HistoryRow>()
.Property(h => h.Model).HasColumnName("metadata"); }

Do I need to call base.OnModelCreating?

Normally, when overriding OnModelCreating, calling the base implementation is optional because it doesn’t actually have any implementation – it is a noop. However, in this case, the base implementation in HistoryContext actually performs the default history model configuration. It currently looks like this:

protected override void OnModelCreating(DbModelBuilder modelBuilder)
        h => new
.Property(h => h.MigrationId).HasMaxLength(255).IsRequired(); modelBuilder.Entity<HistoryRow>()
.Property(h => h.ContextKey).HasMaxLength(512).IsRequired(); modelBuilder.Entity<HistoryRow>()
.Property(h => h.Model).IsRequired().IsMaxLength(); modelBuilder.Entity<HistoryRow>()
.Property(h => h.ProductVersion).HasMaxLength(32).IsRequired(); }

So, calling base.OnModelCreating is required in this case, and we don’t have to worry about configuring the entire history model.

3.     Create an IHistoryContextFactory

Now, we need a way to tell EF to use our derived history context. To do that we need to implement a simple factory method: System.Data.Entity.Migrations.History.IHistoryContextFactory.Create:

public class MyHistoryContextFactory : IHistoryContextFactory
    public HistoryContext Create(
        DbConnection existingConnection, 
bool contextOwnsConnection,
string defaultSchema) { return new MyHistoryContext(
existingConnection, contextOwnsConnection, defaultSchema); } }

4.     Update Migrations Configuration

Finally, we can enable our history context factory by setting it in our derived DbMigrationsConfiguration:

public class Configuration : DbMigrationsConfiguration<MyContext>
    public Configuration()
        AutomaticMigrationsEnabled = false;
        HistoryContextFactory = new MyHistoryContextFactory();

Last edited Oct 3, 2012 at 9:03 PM by AndrewPeters, version 10