64

コードファーストアプローチでEntityFramework4.3を使用するASP.NETMVC3プロジェクトがあります。データベースを最新の状態に保つために移行を使用しています。

プロジェクトはソース管理下にあり、私にはいくつかのブランチがあります。私が今気付いたのは、ブランチの1つをマスターにマージしたいときに問題が発生するということです。両方のブランチに移行ファイルを作成したため、マージすると移行が重複し、競合が発生する可能性があります。

複数のブランチを持つプロジェクトで移行を管理する良い方法はありますか?

アップデート

1つの方法は、ブランチが分離されている間に作成されたすべての移行ファイルをマージしてから削除し、ブランチが作成されてから再びマージされるまでのすべての変更を保持する1つの新しい移行ファイルを作成することです。データベースをダンプし、すべての移行ファイルを使用してデータベースを再構築できるdev-environment。その場合、問題はライブ環境になります。データを失うリスクなしにブランチが作成された時点にロールバックすることはできなかったため、新しい移行ファイルを使用してライブデータベースを更新しようとすると競合が発生します。

4

7 に答える 7

19

同様の質問でエンティティフレームワークの移行マージの競合を処理するためのはるかに優れたソリューションがあります。

マージ後に行う必要があるのは、ターゲットブランチでの移行のメタデータを再スキャフォールディングすることだけです。つまり、アップ/ダウンコードを再スキャフォールドするのではなく、resxファイルの状態だけを再スキャフォールドします。

add-migration [the_migration_to_rescaffold_metadata_for]

これはほとんどの場合機能します。マージ内の別の移行によってデータベースが変更され、移行が実行できなくなったり、予期しない結果が生じたりした場合、この手順は失敗します。そうは言っても、ほとんどの移行は自動生成される必要があるため、または少なくとも移行自体で変更されていない他のテーブルに依存しないようにする必要があるため、非常にまれなケースであると思います。

再足場状態が失敗するそのようなケースの1つは、次のとおりです。

  • 列fooはintであり、行には[0、1、2]が含まれます

  • ブランチAからの移行Afooをbooleanに変更します(0は自動的にfalseになり、> 0はtrueになります)

  • ブランチBからブランチBを移行すると、fooがstringに変更されます。intであることが期待されますが、ブール値ですが、移行は成功します。移行Bが作成されたときに行に["0"、 "1"、 "2"]が含まれるため、データは失われます。列をブール値に変更した場合(正常に実行され、期待される結果が得られた場合)、行には代わりに["0"、 "1"、 "1"]が含まれるようになり、移行Bの最終結果はで観察されたものとは異なります。ブランチB。

ソリューションで問題が発生する可能性のあるエッジケースはおそらくもっと多いでしょう。ただし、移行のアップ/ダウンコードが、マージ内の別の移行によって変更されたものに依存していない場合は、移行内のメタデータを更新するだけでうまくいくはずです。

于 2013-09-09T13:05:02.330 に答える
19

編集:私の同僚はこれを行うのが簡単であることを発見しました、私は完全を期すために私の元の答えを一番下に残しました。

(非常に重要)ライブ環境での移行は、現在のブランチの移行と競合してはなりません。競合しない場合は、すべての移行をやり直して、データモデル変更の競合を手動で解決する必要があります。

  1. ライブ環境データを使用して開発データベースを復元する
  2. 実行するupdate-databaseと、ブランチからの移行が実行され、「現在のモデルに一致するようにデータベースを更新できない」と文句を言う必要があります。
  3. を実行するadd-migration MergeBranchBToMaster -ignoreChangesと、空の移行が作成されます。
  4. update-databaseもう一度実行します
  5. 変更をプッシュする

ステップ3の魔法は、基本的にEFに不一致のモデルについてシャットダウンするように指示します。したがって、移行がライブ環境の移行と競合しないように注意してください。含まれている場合は、不足している移行をプッシュするためのSQLスクリプトをいつでも作成できます(これは実際に推奨される方法です)。

元の回答

@Ladislav Mrnkaの回答に基づいて、かなり簡単な解決策を見つけました。これはライブ環境[1]で機能します。デプロイされた移行を変更しないように注意する必要があります。

  1. マージする前に、追加した移行(MyMigration)と以前の移行(BaseMigration)に注意してください。

  2. gitでブランチをマージする

  3. パッケージマネージャーコンソールを開き、UPDATE-DATABASE -TargetMigration:BaseMigrationを実行します。これにより、競合する移行が適用される前の状態にデータベースが戻ります。

  4. ローカル移行を削除する(MyMigration)

  5. 実行:UPDATE-DATABASE。これにより、他のブランチで行われたすべての新しい移行が適用されます。

  6. 実行:ADD-MIGRATIONMyMigration。これにより、git -rebaseのように、データベースの現在の状態に基づいてローカル移行が再生成されます。

  7. 実行:UPDATE-DATABASE。ローカル移行でデータベースを更新します。

これは、複数のローカル移行がある場合にも機能しますが、それらすべてを1つにマージします。

[1]ライブ環境で作業することにより、生成された移行を、他のブランチの移行の一部またはすべてがすでに適用されている可能性のあるライブ環境に適用できることを意味します。手順自体は、純粋に開発を目的としています。

于 2013-09-17T19:58:41.577 に答える
13

移行のマージはIMHOの手動タスクです。移行コードの一部は自動生成され、通常は自動生成されたコードをマージしません。代わりに、マージ後に自動生成を再度実行します。

ADO.NETチームがいくつかの推奨事項を提供するまで、私は単純な原則に従います。

  • マージを実行する前に、マスターデータベースを分岐前に使用されていたバージョンに戻します
  • ブランチをマージします
  • マージされたアセンブリから分岐後に作成された移行クラスを除外します
  • マージされたコードベースの新しい移行を追加します。これにより、分岐前の状態のデータベースが、ブランチをマージした後の状態に移行されます。
  • 除外された移行クラスにカスタマイズが含まれている場合は、それらを新しい移行クラスにマージします
  • 移行を実行して、データベースを現在のマージされたバージョンに移行します

ブランチに複数の移行ステップ(バージョン)が含まれている場合、それらは失われ、ブランチ前とマージ後の2つのバージョンで終了します。

編集:

ライブ環境では動作しません。ここでの問題は、開発プロセス自体です。ライブ環境がある場合は、そのブランチをそのままにしておく必要があります(マイナーなバグ修正を除く)。そのブランチで本番デプロイメントを使用して開発を継続し、同時に継続的インテグレーションを行わずに別のブランチで別のバージョンをビルドする場合(=変更をメインブランチに継続的にマージして、新しい開発をメインコードベースと統合する)問題。一般的に、移行ではこれを処理できないと思います。

MigrationHistoryこのような場合の唯一のオプションは、マージされたソリューションからすべての移行を削除し、データベースからテーブルを削除することです。プロジェクトで再度移行を有効にし、初期移行を追加して、現在のデータベースを開始点として使用することができます=以前の移行に関する情報が存在しないため、以前のバージョンに戻ることはできません。

于 2012-05-12T11:11:55.843 に答える
11

Rowan Millerは、チャンネル9:移行-チーム環境でこのトピックに関するすばらしいビデオを作成しました。エンティティフレームワーク6を指します。

これは、最初の開発者AとBが同じモデルで作業していて、Aが最初にチェックインするシナリオを説明しています。ここで、開発者Bは、Aから最新バージョンを入手するときに抱える問題に対処する必要があります。

これは基本的に、異なるブランチ間で競合が発生するのと同じです。これは、一般的な問題は、同時に実行された移行の変更をマージすることですが、モデルのソース状態が事実上異なるためです。

解決策は次のとおりです。

  • バージョン管理システムの競合を解決する場合、開発者Bは自分自身と開発者Aの両方からの変更を受け入れる必要があります。
  • この時点では、開発者BのUpdateDatabaseコマンドは引き続き失敗します(エラーメッセージ:「保留中の変更があるため、現在のモデルに一致するようにデータベースを更新できません...」
  • IgnoreChanges開発者Bは、次のオプションを使用して「空の移行」を作成する必要があります。

Add-Migration NameOfMigration -IgnoreChanges

その後、UpdateDatabaseコマンドは成功します。


問題の原因

データベースの更新時に発生するエラーの原因は、EFが、移行が参照するモデルのスナップショットを移行ファイル内のresxファイルに保存するためです。

この場合、「現在のモデル」の開発者Bのスナップショットは、開発者Aによって行われた変更を取得/マージした後は正しくありません。

于 2015-11-19T09:16:45.967 に答える
4

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

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

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

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

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

FirstNameとLastNameを追加します。

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

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

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

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

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

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

于 2013-12-12T09:54:03.143 に答える
2

FluentMigratorやMigrator.NETなど、これらの競合を引き起こさない別の移行ライブラリを使用することを検討してください。

EFの移行は、ブランチやマージで一般的に使用する準備ができているとは思いません。これは大変な作業であり、厄介な間違いを犯すのは簡単すぎます。

于 2013-02-19T13:51:13.563 に答える
0

@LavaEaterが言っていることは非常に理にかなっていると思います。私は分岐戦略(開発、メイン、リリース)を実装し、それを開発、QA、およびリリースプロセスの環境に合わせています。

  • 開発ブランチ-ローカル開発
  • メインブランチ-開発ブランチからの変更をマージし、ステージング環境(Azure WebサイトとSQLデータベース)にデプロイします
  • リリースブランチ-変更をメインからマージし、本番環境(別のAzure WebサイトとSQLデータベース)にデプロイします

私は上記の問題に直面しました。私の意見では、移行に関する複雑さと潜在的な回避策は、リリースプロセスに大きなリスクをもたらします。開発、メイン、リリースで独立した移行を効果的に実行するということは、開発のビルドに含めたスキーマがステージングでQAに入るスキーマではなく、ステージングでQAがサインオフするスキーマがLiveにデプロイされるスキーマではないことを意味します(提案された解決策の1つに従わない限り、これは確実に機能しますが、エラーが発生しやすい可能性があります)。

@LavaEaterをエコーするには-最初にEFコードから得られる本当のメリットは何ですか?個人的には、コードからスキーマを簡単に生成できると思います(必要に応じて、自動生成された移行を微調整することもできます)。その後、移行は単純な展開プロセスの複雑さです。

私の現在の考えは、最初にコードを使用して開発中の移行を生成し、次に次のいずれかを行うことです。

  • オプションA)-Update-Database -scriptを使用して、スキーマの変更をスクリプト化し、ソース管理下に置きます。2人が同じモデルを修正している場合、競合が発生する可能性はまだありますが、管理しやすいと思います。

  • オプションB)-SQL Compareなどを使用して、スキーマ変更スクリプトを生成します。これは、本番データベースに適用しているスキーマの変更を正確に確認したいので、より柔軟で透過的である可能性があります(私をパラノイドと呼びます)。

私は何かが足りないのですか?メインブランチとリリースブランチでコードファーストマイグレーションを無効にするために行うべきいくつかの構成があると思います(DBがスクリプトによって作成および更新されることを前提としています)。それ以外は安全な解決策のように感じますが、セカンドオピニオンを大切にします。

于 2014-03-08T14:36:11.047 に答える