问题
We am using code first EF 4.3.1 with database migrations. Sometimes we drop the database and let EF recreate it, mainly for local development purposes.
There is a procedure which applies pending migrations and when the database is recreated the pending migrations aren't necessary and error is thrown when EF tries to apply them.
I check the migration date from the string and if this is before the database creation date then I manually add it to the __migrationHistory table and don't apply the migration.
This covers most of the scenarios except when someone recreates the database, updates from source control and retrieves oustanding migrations which are before the database creation date.
I have also tried using a try catch around the dbMigrator.Update(migration) method call but if one migrations fails, further ones won't be applied as it remembers the exceptions.
Has anyone found a way to get around this issue?
This is the method I have written:
private static void ApplyMigration<T, TU>()
where T : DbContext, new()
where TU : DbMigrationsConfiguration, new()
{
var migrationsAlreadyApplied = new List<string>();
var dbMigrator = new DbMigrator(new TU());
var creationMigrationId = dbMigrator.GetDatabaseMigrations().Single(m => m.Contains("InitialCreate"));
var dbDateCreated = DateTime.ParseExact(creationMigrationId.Substring(0, 12), Constants.MigrationDateFormat, CultureInfo.InvariantCulture);
dbMigrator.GetPendingMigrations().ToList()
.ForEach(migration =>
{
var migrationDate = DateTime.ParseExact(migration.Substring(0, 12), Constants.MigrationDateFormat, CultureInfo.InvariantCulture);
if (migrationDate > dbDateCreated)
dbMigrator.Update(migration);
else
migrationsAlreadyApplied.Add(migration);
});
using (var dbContext = new T())
{
foreach(var migration in migrationsAlreadyApplied)
dbContext.Database.ExecuteSqlCommand("insert into __MigrationHistory "
+ "select '" + migration + "', Model, ProductVersion "
+ "from __MigrationHistory "
+ "where MigrationId = '" + migration + "'");
}
}
回答1:
I have now resolved this.
In the seed method of my dbContext initialiser, I call a method which will populate the migration history manually. You can then use the ApplyMigrations method to call the migrations normally.
public class UserEntitiesContextInitializer : CreateDatabaseIfNotExists<UserEntitiesContext>
{
protected override void Seed(UserEntitiesContext context)
{
// Update migration history with existing migrations to prevent EF recognising them as pending migrations
DatabaseAdministration.UpdateMigrationHistory<UserEntitiesContext, UserEntitiesContextConfiguration>();
}
}
public static void UpdateMigrationHistory<T, TU>()
where T : DbContext, new()
where TU : DbMigrationsConfiguration, new()
{
using (var dbContext = new T())
{
var dbMigrator = new DbMigrator(new TU());
var creationMigrationId = dbMigrator.GetDatabaseMigrations().Single(m => m.Contains("InitialCreate"));
foreach (var migration in dbMigrator.GetPendingMigrations())
dbContext.Database.ExecuteSqlCommand("insert into __MigrationHistory "
+ "select '" + migration + "', Model, ProductVersion "
+ "from __MigrationHistory "
+ "where MigrationId = '" + creationMigrationId + "'");
}
}
private static void ApplyMigration<T, TU>()
where T : DbContext, new()
where TU : DbMigrationsConfiguration, new()
{
var dbMigrator = new DbMigrator(new TU());
if (dbMigrator.GetPendingMigrations().Any())
dbMigrator.Update(dbMigrator.GetPendingMigrations().Last());
}
来源:https://stackoverflow.com/questions/13155292/ignore-pending-migrations-after-database-recreation