現在、バージョン1ユーザーの既存のコードベースを持つアプリケーションのバージョン2を開発していますが、新しいバージョンを新しいユーザーにロールアウトする必要もあります(つまり、クリーンインストール)。バージョン1はEntityFramework4.1を使用します。バージョン2はEntityFramework5を使用します。
私の問題は、既存のバージョン1ユーザーをバージョン2にアップグレードし、データベースを新しいバージョンのスキーマに移行できるようにする必要があることです。新しいスキーマは、いくつかの新しいテーブルを追加し、いくつかの既存のテーブルを変更せずに残し、他のテーブルを削除します。
旅行中にEF4.1に_MigrationHistory
テーブルが含まれていないことを発見しました。そのため、元のバージョン1コードに戻り、EF5にアップグレードして、次のように初期移行を実行しました。
Add-Migration Initial -IgnoreChanges
これは、元のバージョン1(EF4.1)データベースを移行できるようにする(つまり、_MigrationHistory
テーブルを追加する)ためにうまく機能します。次に、これをバージョン2のコードに移植して、次のコマンドを実行します。
Update-Database
_MigrationHistory
これでテーブルが作成され、次のコマンドを実行します。
Add-Migration Version2
これにより、バージョン2までのデータベースの適切な移行が生成されます。
次のイニシャライザーを使用しているため、データベースがバージョン1スキーマまたはバージョン2スキーマのいずれかに既に存在する場合(後者の場合は移行は適用されません)、これは完全に機能します。
Database.SetInitializer(new MigrateDatabaseToLatestVersion<MyDbContext, Configuration>());
ただし、データベースが存在しない場合、Initial
移行は正常に実行Version2
されますが、移行手順の一部が空のデータベースに明らかに存在しないテーブル、インデックス、および外部キーを削除するため、移行は失敗します。
だから私は完全に途方に暮れています-既存のバージョン1ユーザーをバージョン2に移行する(そしてそれらのデータを保持する)だけでなく、データベースを完全にゼロから作成する必要がある新しいインストールをサポートするにはどうすればよいですか?
移行するSQLスクリプトの作成と実行について多くのアイデアを見てきましたが、アプリの起動時にこれを自動的に実行する必要があります。エンドユーザーは、実際にはMSIファイルを実行するだけでアップグレードできます。
更新:w.brianが以下に提案する解決策は次のとおりです(申し訳ありませんが、まだ賛成できません):
string connectionString = ConfigurationManager.ConnectionStrings["DbContext"].ConnectionString;
if (Database.Exists(connectionString))
{
Database.SetInitializer(new MigrateDatabaseToLatestVersion<DbContext, Migrations.Configuration>());
}
else
{
Database.SetInitializer(new DefaultDataInitialiser());
}
UPDATE2:上記は、新しい作成を通じて初めて機能するようです。ただし、次の実行はDatabase.Exists()
チェックに合格し、データベースの移行を試みます。ただし、_MigrationHistory
テーブルには(new / clean installによって生成された)エントリが1つしかなく、移行には2つのエントリ(EF4.1移行用に1つ、新しいスキーマ用に1つ)があるため、移行ロジックは最初から開始されます。そして、各移行を適用しようとします。
これは、データベースにすでに存在するテーブルを作成しようとするため失敗します。クリーンインストールの一部としてこれらを作成しました。
つまり、このアプローチの核心は、移行ロジックを台無しにすることです。
UPDATE3:最初のデータベースを作成し、その後の実行で移行のみを適用できるようにする方法を理解したと思います。上記から、データベースがすでに存在する場合は、移行コードを続行します。
データベースがまだ存在しない場合はDefaultDataInitialiser
、メソッドでandを使用してSeed()
、次の手順を実行します。
context.Database.ExecuteSqlCommand(@"DELETE FROM [__MigrationHistory]");
byte[] version1Model = ConvertHexStringToByteArray("1F8B...");
context.Database.ExecuteSqlCommand(@"INSERT INTO [__MigrationHistory]
([MigrationId]
,[Model]
,[ProductVersion])
VALUES
('201302082120145_Initial'
,{0}
,'5.0.0.net40')", new object[] { version1Model });
byte[] version2Model = ConvertHexStringToByteArray("1F8B...");
context.Database.ExecuteSqlCommand(@"INSERT INTO [__MigrationHistory]
([MigrationId]
,[Model]
,[ProductVersion])
VALUES
('201302082200350_Version-2'
,{0}
,'5.0.0.net40')", version2Model);
これにより、移行ロジックの観点から、新しいデータベースが「完全に移行」されます。次にアプリケーションを実行すると、データベースが存在し、MigrateDatabaseToLatestVersion
マジックが実行され、データベースが最新バージョン(または将来の次の移行へのアップグレード)であり、満足していることがわかります。
Seed()
残念ながら、データベースを最初から作成する場合は、将来、すべての新しい移行をこのメソッドに追加する必要があります。
そして、モデルに使用される16進文字列はどこで入手できましたか?移行したバージョンのデータベースからSQLServerManagementStudioからコピーしました。