50

EntityFramework5.0を使用するプロジェクトに複数の開発者が取り組んでいます。すべての開発者は自分のローカルSQL2012データベースを使用するため、他の開発者の邪魔をすることなく開発とテストを行うことができます。

最初は、自動移行とコードベースの移行のハイブリッドを使用しました。それはまったくうまくいかなかったので、自動移行を無効にし、コードベースのみを許可することにしました。_MigrationsHistoryすべての自動移行による「破損」のないクリーンなデータベースから再開したことを付け加えておきます。

したがって、ワークフローは次のようになります。

  1. 開発者がデータモデルを変更する
  2. を使用してデータベースadd-migration <Name>に適用しますupdate-database
  3. データモデルの変更とGitへの移行をチェックインします。
  4. 別の開発者がプルして変更を受け取り、それを自分のデータベースに適用します。

これまでのところ、これはうまくいきました。しかし、今日以前は、通常、移行を行ったのは私だけであり、他の人がそれらを適用していました。しかし、今日、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/

上記のプロジェクトがある場合に再現する手順(これらの手順はコードにも含まれています):

  1. add-migration Init
  2. update-database(データベース'TestDb'上)
  3. TestDb1を指すように接続文字列を変更します
  4. TestDb1の更新データベース
  5. クラステストでプロパティFooのコメントを解除します
  6. add-migration M1を使用して、プロパティFooをTestDb1に追加します
  7. Test.Fooをもう一度コメントアウトします
  8. TestDb2を指すように接続文字列を変更します
  9. プロジェクトから移行M1を除外して、TestDb2に適用されないようにします。
  10. クラステストのプロパティバーのコメントを解除します
  11. Update-データベースを更新して、初期移行をTestDb2に適用します
  12. add-migration M2を使用して、プロパティバーをTestDb2に追加します
  13. 元のTestDbを再び指すように接続文字列を変更します
  14. 移行M1をプロジェクトに再度含めます
  15. クラステストでプロパティFooのコメントを解除します
  16. クラスTestのプロパティSomeIntのコメントを解除します
  17. データベースを更新する
  18. 追加移行M3
  19. update-database、M3が移行M1によってすでに追加されたデータベースTestDbに列Fooを追加しようとするため、エラーが発生します。

上記は、3人のユーザーをシミュレートするためのもので、ユーザー1がデータベースを初期化し、他の2人は初期化を使用してデータベースを作成します。次に、ユーザー2とユーザー3の両方がデータモデルに独自の変更を加え、変更を適用するために必要な移行とともにソース管理に追加します。次に、ユーザー1がユーザー2と3の変更をプルし、ユーザー1もデータベースに変更を加えました。次に、ユーザー1はupdate-database、ユーザー2と3の変更を適用するために呼び出します。次に、ユーザー1は自分の移行をスキャフォールディングし、ユーザー2または3からスキャフォールド移行に誤って変更を追加します。これにより、ユーザー1のデータベースに適用するとエラーが発生します。

4

9 に答える 9

20

.resxファイル内の最新の移行のスナップショットをリセットする空白の「マージ」移行を追加する必要があります。IgnoreChangesスイッチを使用してこれを行います。

Add-Migration <migration name> -IgnoreChanges

説明はこちらをご覧ください

于 2014-04-01T21:47:14.277 に答える
6

コードの競合と同じように、移行の競合を手動で解決する必要があります。更新して新しい移行がある場合は、最後の移行の背後にあるメタデータが現在のモデルと一致していることを確認する必要があります。移行のメタデータを更新するには、そのメタデータに対してAdd-Migrationコマンドを再発行します。

たとえば、シナリオのステップ17(Update-Database)の前に、次のコマンドを発行する必要があります

Add-Migration M2

これにより、メタデータが更新され、現在のモデルと同期されます。これで、M3を追加しようとすると、それ以上モデルを変更していないため、空白になっているはずです。

于 2012-11-12T18:13:48.237 に答える
5

オプション1:空白の「マージ」移行を追加する

  1. ローカルコードベースで保留中のモデル変更が移行に書き込まれていることを確認します。この手順により、空白の移行を生成するときに正当な変更を見逃さないようにすることができます。
  2. ソース管理と同期します。
  3. Update-Databaseを実行して、他の開発者がチェックインした新しい移行を適用します。**注:**** Update-Databaseコマンドから警告が表示されない場合、他の開発者からの新しい移行はなく、それ以上のマージを実行する必要はありません。
  4. Add-Migration –IgnoreChangesを実行します(例:Add-Migration Merge –IgnoreChanges)。これにより、すべてのメタデータ(現在のモデルのスナップショットを含む)を含む移行が生成されますが、現在のモデルを最後の移行のスナップショットと比較したときに検出された変更はすべて無視されます(つまり、空白のUpおよびDownメソッドを取得します)。
  5. 開発を続行するか、ソース管理に送信します(もちろんユニットテストを実行した後)。

オプション2:最後の移行でモデルスナップショットを更新する

  1. ローカルコードベースで保留中のモデル変更が移行に書き込まれていることを確認します。この手順により、空白の移行を生成するときに正当な変更を見逃さないようにすることができます。
  2. ソース管理と同期します。
  3. Update-Databaseを実行して、他の開発者がチェックインした新しい移行を適用します。**注:**** Update-Databaseコマンドから警告が表示されない場合、他の開発者からの新しい移行はなく、それ以上のマージを実行する必要はありません。
  4. Update-Database –TargetMigrationを実行します(これまでの例では、Update-Database –TargetMigration AddRatingになります)。これにより、データベースは最後から2番目の移行の状態に戻ります。つまり、データベースからの最後の移行を事実上「適用解除」します。**注:****メタデータはデータベースの__MigrationsHistoryTableにも保存されるため、この手順は、移行のメタデータを安全に編集できるようにするために必要です。これが、最後の移行がローカルコードベースのみにある場合にのみこのオプションを使用する必要がある理由です。他のデータベースに最後の移行が適用されている場合は、それらをロールバックし、最後の移行を再適用してメタデータを更新する必要があります。
  5. Add-Migrationを実行します(これまでの例では、これはAdd-Migration 201311062215252_AddReadersのようになります)。**注:****新しい移行をスキャフォールディングするのではなく、既存の移行を編集することを移行が認識できるように、タイムスタンプを含める必要があります。これにより、最後の移行のメタデータが現在のモデルと一致するように更新されます。コマンドが完了すると次の警告が表示されますが、それはまさにあなたが望むものです。「移行用のDesignerコード「201311062215252_AddReaders」のみが再スキャフォールドされました。移行全体を再スキャフォールディングするには、-Forceパラメーターを使用します。」
  6. Update-Databaseを実行して、更新されたメタデータを使用して最新の移行を再適用します。
  7. 開発を続行するか、ソース管理に送信します(もちろんユニットテストを実行した後)。

MSDNには、これに関するすばらしい記事があります。それを通過してください。

チーム環境でのEntityFrameworkコードの最初の移行

于 2017-08-07T10:38:48.380 に答える
2

私たちの環境でも同様の問題が発生しています。これまでにわかったことと、それをどのように回避したかを次に示します。

適用した変更(update-database)があり、チェックインしていない場合、変更がない別の開発者から変更を受け取った場合、これは物事が同期していないように見える場所です。私たちの経験では、自分の変更のために保存されたメタデータは、データベースの更新プロセスを実行するときに、他の開発者からのメタデータによって上書きされるようです。他の開発者はあなたの変更を持っていないので、保存されるメタデータはもはやあなたのデータベースの実際の反映ではありません。その後EFが比較を行うと、メタデータの変更により、変更が実際に新しいものであると「考えられます」。

単純で明らかに醜い回避策は、別の移行を実行し、その内容を消去して、empty up()メソッドとempty down()メソッドを使用することです。その移行を適用してソース管理にチェックインし、全員がそれに同期できるようにします。これは単にすべてのメタデータを同期するので、すべての変更が考慮されます。

于 2012-11-13T04:37:46.103 に答える
1

私はcodeplexに問題を追加しました。この問題は、私たちのチームにも多くの頭を悩ませています。

リンクはhttps://entityframework.codeplex.com/workitem/1670です。

于 2013-09-18T14:07:45.570 に答える
1

私はこれについていくらか考えました。ここに提示されたさまざまな意見や慣行に貢献したいと思います。

ローカル移行が実際に何を表しているかを検討してください。開発データベースをローカルで操作する場合、テーブルに列などを追加したり、新しいエンティティを追加したりするときに、可能な限り最も便利な方法でデータベースを更新するために移行を使用します。

したがって、Add-Migrationは、現在のモデル(モデルbと呼びます)を以前のモデル(モデルa)と照合し、データベース内のa=>bから移行するための移行を生成します。

誰もが実際に独自のデータベースを持っていて、組織内にある種のステージ/テスト/開発/本番データベースサーバーが存在する場合、自分の移行を他の人の移行とマージしようとすることはほとんど意味がありません。これはすべて、チームがどのように設定したかによって異なりますが、本当に分散して作業したい場合は、他の人が行った変更からお互いを隔離することは理にかなっています。

さて、あなたが分散して仕事をしていて、あなたが取り組んでいるエンティティ、例えば、Personを持っているなら。どういうわけか、他の多くの人々もそれに取り組んでいます。したがって、スプリントの特定のストーリーの必要に応じて、Personのプロパティを追加および削除します(ここではすべてアジャイルに取り組んでいますね)。たとえば、社会保障番号を最初に整数にしたのは、あなたがそうではないためです。その明るいそしてそれからひもなどに。

FirstNameとLastNameを追加します。

その後、完了し、10個の奇妙な上下の移行があり(それらはただのがらくただったので、おそらく作業中にそれらのいくつかを削除しました)、中央のGitリポジトリからいくつかの変更をフェッチします。わお。あなたの同僚のボブもいくつかの名前を必要としていました、多分あなたはお互いに話し合うべきでしたか?

とにかく、彼はNameFirstとNameLastを追加しました、私は推測します...それで、あなたは何をしますか?さて、あなたはマージし、リファクタリングし、変更して、より正しい名前を付けます... FirstNameやLastNameのように、テストを実行して彼のコードをチェックしてから、中央にプッシュします。

しかし、移行についてはどうでしょうか?さて、今が中央リポジトリを移動する移行を行うときです。より具体的には、ブランチの「テスト」には、モデルa=>モデルbからのちょっとした移行が含まれています。この移行は、10の奇妙な移行ではなく、1つだけの移行になります。

私が何をしているのか分かりますか?私たちは素敵な小さなポコを使って作業しており、それらの比較が実際の移行を構成しています。したがって、移行をマージするべきではありません。私の意見では、ブランチごとの移行などを行う必要があります。

実際、マージ後にブランチで移行を作成する必要がありますか?はい、このデータベースが自動的に更新される場合は、更新する必要があります。

考慮すべきもう1つのことは、中央リポジトリからプルを実行する前に、実際に移行を作成しないことです。つまり、移行を作成する前に、他のチームメンバーの移行コードモデルへの変更の両方を取得します。

もう少し作業する必要があります。少なくとも、これについての私の考えです。

于 2013-12-12T10:00:40.983 に答える
0

私が思いついた解決策(少なくとも2人のユーザーについては、3人についてはテストしていません)は次のとおりです。

  1. 移行をマージしてメタデータを同期し、update-databaseを実行します(これは失敗するはずです)。
  2. データベースを追加してから
  3. で生成されたすべてのコードup()down()メソッドを削除します

これは引き続き更新データベースによって実行されますが、メタデータを同期するだけで何も実行されません。

于 2013-11-07T17:26:25.997 に答える
0

@LavaEaterに同意します。問題の核心は、移行の足場を一元化する必要があるということです。おそらく、プッシュが発生するたびに、自動化/統合されたビルドプロセスの一部としてですか?その後、結果として生じる移行は、チームメンバーによってサーバーからプルできます。

これは、独自の移行スクリプトをサーバーにプッシュしないことを意味します。

于 2014-02-24T19:02:56.067 に答える
0

移行でマージの競合/エラーが発生しないようにする簡単な方法があります。

  1. いつでも行うように、ブランチで作業します。
  2. マスターにマージしてマージエラーが発生した場合:
  3. フォルダからすべての*.csファイルを削除しmigrationsます。
  4. フォルダgit checkout master ./*内で行います。migrations
  5. 移行を再作成します。
  6. スナップショットはup2dateであり、マージの競合はありません。
  7. また、プルリクエストをマスターにマージする直前に、マスターとマージして、常に手順3〜6を実行する必要があります。

以下は、手順3〜6を実行する単純なPowershellスクリプトです。

function Write-Info($text)
{
    Write-Color "$pwd", "> ", "$text" -Colour "Yellow", "Blue", "White"
}
function Create-Migration($project, $migrationName, $referenceBranch)
{
    Set-Location "$SolutionPath\$project"
    Write-Info "Going to migrations"
    Set-Location "Migrations"
    Write-Info "Removing ./*.cs"
    Remove-Item ./*.cs
    Write-Info "git fetch --all"
    git fetch --all
    Write-Info "git checkout origin/$referenceBranch ./*"
    git checkout origin/$referenceBranch ./*
    Set-Location ..
    Write-Info "Creating migration $migrationName "
    dotnet ef migrations add "$migrationName"
}

私はこの半年間その方法で働いています。移行に関しては、0マージの競合を解決して解決します8)。

于 2021-02-11T11:00:47.543 に答える