EntityFramework5.0を使用するプロジェクトに複数の開発者が取り組んでいます。すべての開発者は自分のローカルSQL2012データベースを使用するため、他の開発者の邪魔をすることなく開発とテストを行うことができます。
最初は、自動移行とコードベースの移行のハイブリッドを使用しました。それはまったくうまくいかなかったので、自動移行を無効にし、コードベースのみを許可することにしました。_MigrationsHistory
すべての自動移行による「破損」のないクリーンなデータベースから再開したことを付け加えておきます。
したがって、ワークフローは次のようになります。
- 開発者がデータモデルを変更する
- を使用してデータベース
add-migration <Name>
に適用しますupdate-database
。 - データモデルの変更とGitへの移行をチェックインします。
- 別の開発者がプルして変更を受け取り、それを自分のデータベースに適用します。
これまでのところ、これはうまくいきました。しかし、今日以前は、通常、移行を行ったのは私だけであり、他の人がそれらを適用していました。しかし、今日、3人の開発者からの移行がありました。私はそれらの移行を引っ張っただけで、うまくいきましたupdate-database
。
また、自分のデータモデルに変更を加えたので、最後に、update-database
まだ最新ではないという警告が表示されたので、変更しましたadd-migration <my migration>
。ただし、移行の足場を組むと、データベースにすでに適用したすべての移行の変更が表示されました。つまり、すでに削除されている列を削除しようとしたり、既存のテーブルを作成しようとしたりしました。
どうしてそれができるのでしょうか?私の仮定では、EFはテーブルをチェックして_MigrationsHistory
、テーブルにまだ存在していない移行を見つけ、名前の一部であるタイムスタンプ順に並べて適用します。しかし、明らかにそうではありません。自分の変更を元に戻し、クリーンな環境を使用している場合でも、データベースがモデルと同期していないと文句を言うからです。しかし、私はそれらの変更をプルしてデータベースに適用しました。同期しています。先ほど適用した移行も_MigrationsHistory
表に表示されます。
私が考えることができる唯一のことは、データベースの変更をもたらさないプロパティをデータモデルに追加したことです(List<X>
Xが1対多の関係で多数であるデータモデルYにを追加しました。これはそうではありませんXにはすでにYへの外部キーがあるため、データベースが変更されます)。それでいいの?もしそうなら、データベースの変更がなく、これを修正する方法もわからないため、移行を追加する方法がないため、これは非常に脆弱です。
もちろん、足場を編集して、データベースにすでに適用されているものをすべて削除できるため、これに対処する方法がわかりません。しかし、それでは何ですか?私がチェックインすると、他の開発者は、新しい変更を適用した後でもデータベースが最新ではないという同じメッセージを受け取り、自分の変更をスキャフォールディングし、同じナンセンスなスキャフォールディングを取得し、編集し、チェックインしてから次の開発者はそれを取得します。それは悪循環になり、自動移行を使用したときと同じようなものになり、コードベースのみに切り替えることでそれを修正したと思いました。私は今、正しいことをすることを信じることができず、このように働くことは悪夢です。
私も試したのは、同僚から引き出した移行を1つずつ追加することですが、update-database -t:201211091112102_<migrationname>
役に立ちませんでした。それでも私に誤った足場を与えます。
では、ここで何を間違えたのでしょうか。それとも、EFはこのようなコラボレーションのために構築されたものではないのでしょうか。
アップデート
再現可能なテストケースを作成しましたが、このマルチユーザー/マルチデータベースのシナリオをシミュレートするために、少し長いダンスです。
https://github.com/JulianR/EfMigrationsTest/
上記のプロジェクトがある場合に再現する手順(これらの手順はコードにも含まれています):
- add-migration Init
- update-database(データベース'TestDb'上)
- TestDb1を指すように接続文字列を変更します
- TestDb1の更新データベース
- クラステストでプロパティFooのコメントを解除します
- add-migration M1を使用して、プロパティFooをTestDb1に追加します
- Test.Fooをもう一度コメントアウトします
- TestDb2を指すように接続文字列を変更します
- プロジェクトから移行M1を除外して、TestDb2に適用されないようにします。
- クラステストのプロパティバーのコメントを解除します
- Update-データベースを更新して、初期移行をTestDb2に適用します
- add-migration M2を使用して、プロパティバーをTestDb2に追加します
- 元のTestDbを再び指すように接続文字列を変更します
- 移行M1をプロジェクトに再度含めます
- クラステストでプロパティFooのコメントを解除します
- クラスTestのプロパティSomeIntのコメントを解除します
- データベースを更新する
- 追加移行M3
- update-database、M3が移行M1によってすでに追加されたデータベースTestDbに列Fooを追加しようとするため、エラーが発生します。
上記は、3人のユーザーをシミュレートするためのもので、ユーザー1がデータベースを初期化し、他の2人は初期化を使用してデータベースを作成します。次に、ユーザー2とユーザー3の両方がデータモデルに独自の変更を加え、変更を適用するために必要な移行とともにソース管理に追加します。次に、ユーザー1がユーザー2と3の変更をプルし、ユーザー1もデータベースに変更を加えました。次に、ユーザー1はupdate-database
、ユーザー2と3の変更を適用するために呼び出します。次に、ユーザー1は自分の移行をスキャフォールディングし、ユーザー2または3からスキャフォールド移行に誤って変更を追加します。これにより、ユーザー1のデータベースに適用するとエラーが発生します。