Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
EF: Bundle Seed code with Migration classes for seeding per migration
using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.Data.Entity.Migrations;
using System.Linq;
using System.Text.RegularExpressions;
/// <summary>
/// Provides advanced migrations by providing a seeding platform for each migration.
/// This allows for initial seed data after each new database version (for example when
/// deploying new features and you want to include initial data). Seeders will be executing
/// in the correct order after all migrations have been completed.
/// </summary>
public class DbSeederMigrator<TContext> : DbMigrator where TContext : DbContext, new()
{
private static readonly Regex _migrationIdPattern = new Regex(@"\d{15}_.+");
private const string _migrationTypeFormat = "{0}.{1}, {2}";
private const string _automaticMigration = "AutomaticMigration";
/// <summary>
/// Initializes a new instance of the DbMigrator class.
/// </summary>
/// <param name="configuration">Configuration to be used for the migration process.</param>
public DbSeederMigrator(DbMigrationsConfiguration configuration)
: base(configuration)
{ }
/// <summary>
/// Migrates the database to the latest version
/// </summary>
public void MigrateToLatestVersion()
{
var seedList = new List<IMigrationDataSeeder<TContext>>();
// Apply migrations
foreach (var migrationId in GetPendingMigrations())
{
if (IsAutomaticMigration(migrationId))
continue;
if(!IsValidMigrationId(migrationId))
continue;
var migration = GetMigrationFromClassName(migrationId);
var migrationSeeder = GetSeederFromMigration(migration);
// Call the actual update to execute this migration
base.Update(migrationId);
if (migrationSeeder != null)
seedList.Add(migrationSeeder);
}
// Create a new datacontext using the generic type provided
TContext databaseContext = new TContext();
// Apply data seeders
foreach (var migrationSeeder in seedList)
{
migrationSeeder.Seed(databaseContext);
}
}
/// <summary>
/// Gets the IMigrationDataSeeder from the DbMigration if the interface was implemented
/// </summary>
/// <param name="migration">The instance of the migration to seed</param>
/// <returns>The migration instance typed as IMigrationDataSeeder</returns>
private IMigrationDataSeeder<TContext> GetSeederFromMigration(DbMigration migration)
{
return migration as IMigrationDataSeeder<TContext>;
}
/// <summary>
/// Creates a full type instance for the migration id by using the current migrations namespace
/// ie: Project.Core.Data.Migrations.34589734533_InitialCreate
/// </summary>
/// <param name="migrator">The migrator context</param>
/// <param name="migrationId">The migration id from the migrations list of the migrator</param>
/// <returns>The full DbMigration instance</returns>
private DbMigration GetMigrationFromMigrationId(string migrationId)
{
string migrationTypeName =
string.Format(_migrationTypeFormat,
Configuration.MigrationsNamespace,
GetMigrationClassName(migrationId),
Configuration.MigrationsAssembly.FullName);
return CreateTypeInstance<DbMigration>(migrationTypeName);
}
/// <summary>
/// Creates a new instance of a typename
/// </summary>
/// <typeparam name="TType">The type of the return instance</typeparam>
/// <param name="typeName">The full name (including assembly and namespaces) of the type to create</param>
/// <returns>
/// A new instance of the type if it is (or boxable to) <typeparamref name="TType"/>,
/// otherwise the default of <typeparamref name="TType"/>
/// </returns>
private TType CreateTypeInstance<TType>(string typeName) where TType : class
{
Type classType = Type.GetType(typeName, false);
if (classType == null)
return default(TType);
object newType = Activator.CreateInstance(classType);
return newType as TType;
}
#region "Migration ID validation"
/// <summary>
/// Checks if the migration id is valid
/// </summary>
/// <param name="migrationId">The migration id from the migrations list of the migrator</param>
/// <returns>true if valid, otherwise false</returns>
/// <remarks>
/// This snippet has been copied from the EntityFramework source (http://entityframework.codeplex.com/)
/// </remarks>
private bool IsValidMigrationId(string migrationId)
{
if (string.IsNullOrWhiteSpace(migrationId))
return false;
return _migrationIdPattern.IsMatch(migrationId)
|| migrationId == DbMigrator.InitialDatabase;
}
/// <summary>
/// Checks if the the migration id belongs to an automatic migration
/// </summary>
/// <param name="migrationId">The migration id from the migrations list of the migrator</param>
/// <returns>true if automatic, otherwise false</returns>
/// <remarks>
/// This snippet has been copied from the EntityFramework source (http://entityframework.codeplex.com/)
/// </remarks>
private bool IsAutomaticMigration(string migrationId)
{
if (string.IsNullOrWhiteSpace(migrationId))
return false;
return migrationId.EndsWith(_automaticMigration, StringComparison.Ordinal);
}
/// <summary>
/// Gets the ClassName from a migration id
/// </summary>
/// <param name="migrationId">The migration id from the migrations list of the migrator</param>
/// <returns>The class name for this migration id</returns>
/// <remarks>
/// This snippet has been copied from the EntityFramework source (http://entityframework.codeplex.com/)
/// </remarks>
private string GetMigrationClassName(string migrationId)
{
if (string.IsNullOrWhiteSpace(migrationId))
return string.Empty;
return migrationId.Substring(16);
}
#endregion
}
public partial class InitialCreate : DbMigration, IMigrationDataSeeder<DataContext>
{
public override void Up(){
// Some migration Code
}
public override void Down(){
// Some migration Code
}
public void Seed(DataContext context)
{
// Some seed code, the same as you would do in the Configuration Seed method
context.SaveChanges();
}
}
/// <summary>
/// Provides data seeding capabities to the EF Migration classes
/// </summary>
public interface IMigrationDataSeeder<TContext> where TContext : DbContext
{
/// <summary>
/// Seeds this migration
/// </summary>
void Seed(TContext context);
}
var configuration = new Configuration();
var migrator = new DbSeederMigrator<DataContext>(configuration);
migrator.MigrateToLatestVersion();
@prabhakarreddy1234

This comment has been minimized.

Copy link

@prabhakarreddy1234 prabhakarreddy1234 commented Sep 12, 2016

I am not sure where to create an instance of Configuration. I think this will be done by EF itself. How can i intercept this in my code.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.