I\'ve enabled code-first migrations on my entity framework project, and have added several migrations which do things like rename tables. However, I have now deleted the databa
This implementation does not need to manually maintain records to be inserted to __MigrationHistory
. Migrations are determined from assembly specified.
Maybe this helps.
My thanks goes to @Jez for initial idea.
///
/// An implementation of IDatabaseInitializer that will:
/// 1. recreate database only if the database does not exist
/// 2. actualize __MigrationHistory to match current model state (i.e. latest migration)
///
/// The type of the context.
public class CreateDatabaseIfNotExistsAndMigrateToLatest : CreateDatabaseIfNotExists
where TContext : DbContext
{
private readonly Assembly migrationsAssembly;
///
/// Gets the migration metadata for types retrieved from . Types must implement .
///
/// The assembly.
///
private static IEnumerable GetMigrationMetadata(Assembly assembly)
{
var types = assembly.GetTypes().Where(t => typeof(IMigrationMetadata).IsAssignableFrom(t));
var migrationMetadata = new List();
foreach (var type in types)
{
migrationMetadata.Add(
(IMigrationMetadata)Activator.CreateInstance(type));
}
return migrationMetadata.OrderBy(m => m.Id);
}
///
/// Gets the provider manifest token.
///
/// The db.
///
private static string GetProviderManifestToken(TContext db)
{
var connection = db.Database.Connection;
var token = DbProviderServices.GetProviderServices(connection).GetProviderManifestToken(connection);
return token;
}
///
/// Gets the migration SQL generator. Currently it is .
///
///
private static MigrationSqlGenerator GetMigrationSqlGenerator()
{
return new SqlServerMigrationSqlGenerator();
}
///
/// Creates the operation for inserting into migration history. Operation is created for one .
///
/// The migration metadatum.
///
private static InsertHistoryOperation CreateInsertHistoryOperation(IMigrationMetadata migrationMetadatum)
{
var model = Convert.FromBase64String(migrationMetadatum.Target);
var op = new InsertHistoryOperation(
"__MigrationHistory",
migrationMetadatum.Id,
model,
null);
return op;
}
///
/// Generates the SQL statements for inserting migration into history table.
///
/// The generator.
/// The operation.
/// The token.
///
private static IEnumerable GenerateInsertHistoryStatements(
MigrationSqlGenerator generator,
InsertHistoryOperation op,
string token)
{
return generator.Generate(new[] { op }, token);
}
///
/// Runs the SQL statements on database specified by ( ).
///
/// The statements.
/// The db.
private static void RunSqlStatements(IEnumerable statements, TContext db)
{
foreach (var statement in statements)
{
db.Database.ExecuteSqlCommand(statement.Sql);
}
}
///
/// Initializes a new instance of the class.
///
/// The migrations assembly.
public CreateDatabaseIfNotExistsAndMigrateToLatest(Assembly migrationsAssembly)
{
this.migrationsAssembly = migrationsAssembly;
}
protected override void Seed(TContext context)
{
base.Seed(context);
// Get migration metadata for migrationAssembly
var migrationMetadata = GetMigrationMetadata(migrationsAssembly);
// Crate DbContext
var db = Activator.CreateInstance();
// Remove newly created record in __MigrationHistory
db.Database.ExecuteSqlCommand("DELETE FROM __MigrationHistory");
// Get provider manifest token
var token = GetProviderManifestToken(db);
// Get sql generator
var generator = GetMigrationSqlGenerator();
foreach (var migrationMetadatum in migrationMetadata)
{
// Create history operation
var op = CreateInsertHistoryOperation(migrationMetadatum);
// Generate history insert statements
var statements = GenerateInsertHistoryStatements(generator, op, token);
// Run statements (SQL) over database (db)
RunSqlStatements(statements, db);
}
}
}