2

データベースの移行では、コード ファーストの EF 4.3.1 を使用しています。主にローカル開発の目的で、データベースを削除して EF に再作成させることがあります。

保留中の移行を適用する手順があり、データベースが再作成されると、保留中の移行は不要になり、EF がそれらを適用しようとするとエラーがスローされます。

文字列から移行日を確認し、これがデータベースの作成日より前である場合は、手動で __migrationHistory テーブルに追加し、移行を適用しません。

これは、誰かがデータベースを再作成し、ソース管理から更新し、データベースの作成日より前の未解決の移行を取得する場合を除いて、ほとんどのシナリオをカバーしています。

また、dbMigrator.Update(migration) メソッド呼び出しで try catch を使用してみましたが、1 つの移行が失敗すると、例外が記憶されているため、それ以上の移行は適用されません。

この問題を回避する方法を見つけた人はいますか?

これは私が書いた方法です:

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 + "'");
    }
}
4

1 に答える 1

4

これで解決しました。

dbContext イニシャライザーのシード メソッドで、移行履歴を手動で入力するメソッドを呼び出します。その後、ApplyMigrations メソッドを使用して、通常どおり移行を呼び出すことができます。

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());
    }
于 2012-11-06T10:02:56.713 に答える