web-dev-qa-db-ja.com

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

コードファーストアプローチでEntity Framework 4.3を使用するASP.NET MVC3プロジェクトがあります。マイグレーションを使用して、データベースを最新の状態に保ちます。

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

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

更新

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

53

受け入れられた答えは間違っていると思います。 エンティティフレームワークの移行とマージの競合を処理するためのはるかに優れたソリューション が同様の質問にあります。

マージ後に行う必要があるのは、移行先のブランチで移行のメタデータを再足場することだけです。つまり、アップ/ダウンコードを再スカフォールドせず、resxファイル内の状態だけを再スカフォールドします。

add-migration [the_migration_to_rescaffold_metadata_for]

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

そのようなケースの1つはfxpです(より良い例は考えられませんでした)

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

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

  • ブランチBから移行Bはfooを文字列に変更します。それはintであると想定していますが、ブール値であるため、移行は成功します。移行Bが作成されたときに行に["0"、 "1"、 "2"]が含まれるため、データが失われます。移行Aが列をブール値に変更した場合(正常に実行され、期待どおりの結果が得られた場合)、行には代わりに["0"、 "1"、 "1"]が含まれ、移行Bは支店B.

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

17
oldwizard

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

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

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

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

元の回答

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

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

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

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

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

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

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

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

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

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

15
Bill Yang

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

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

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

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

編集:

ライブ環境では機能しません。ここでの問題は、開発プロセスそのものです。ライブ環境がある場合は、ブランチに手を付けないでください(マイナーなバグ修正を除く)。実稼働展開を使用してそのブランチで開発を継続し、同時に継続的な統合なしで別のブランチで別のバージョンをビルドする場合(=メインブランチに変更を継続的にマージして、新しい開発をメインコードベースに統合する)問題。一般に、移行ではこれを処理できないと思います。

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

13
Ladislav Mrnka

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

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

これは、異なるブランチ間で競合が発生するのと本質的に同じです。一般的な問題は、同時に行われた移行の変更をマージするが、モデルの異なるソース状態を効果的に持っているためです。

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

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

Add-Migration NameOfMigration -IgnoreChanges

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


問題の原因

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

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

9
Martin

私はこれにいくつかの考えを入れました、そして、私はここに提示された異なる意見と実践に貢献することを望みます。

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

そのため、Add-Migrationはmy現在のモデル(model bと呼びます)をmy以前のモデル(model a)に対してチェックし、aからbへの移行を生成します。データベース。

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

まあ、もしあなたが分散して働いていて、あなたが取り組んでいるエンティティ、例えばPersonを持っているなら。何らかの理由で、他の多くの人々もそれに取り組んでいます。そのため、スプリントの特定のストーリーに必要な場合はPersonのプロパティを追加および削除します(私たちは全員ここでアジャイルに取り組んでいますよね?)、あなたが最初に整数にした社会保障番号のようにその明るいし、文字列などに.

FirstNameとLastNameを追加します。

これで完了です。10回の奇妙な上下の移行が行われ(たぶんただのがらくただったので、作業中にそれらのいくつかを削除したのでしょう)、中央のGitリポジトリからいくつかの変更を取得します。ワオ。あなたの同僚のボブもいくつかの名前を必要としていました、おそらくあなたはお互いに話すべきだったのでしょうか?

とにかく、彼はNameFirstとNameLastを追加したと思います...それで、あなたはどうしますか?マージ、リファクタリング、変更を行って、FirstNameやLastNameなどのより適切な名前を付けます。テストを実行してコードを確認し、中央にプッシュします。

しかし、移行についてはどうでしょうか?さて、今が中央リポジトリを移動する移行、またはより具体的にはブランチ "test"にits model a => model bからの素敵な小さな移行を含めるときです。この移行は、10回の奇妙な移行ではなく、たった1回の移行になります。

私が何を得ているかわかりますか?私たちはニースの小さなポコと協力しており、それらの比較が実際の移行を構成しています。したがって、移行をまったくマージしないでください。ブランチごとの移行などが必要です。

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

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

4
LavaEater

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

EFの移行は、ブランチとマージで一般的に使用する準備が本当に整っていないと思います-それは多くの作業であり、厄介な間違いを犯すのは簡単すぎます。

2
Eamon Nerbonne

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

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

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

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

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

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

  • オプションB)-SQL Compareなどを使用して、スキーマ変更スクリプトを生成します。実稼働データベースにどのスキーマ変更が適用されているかを正確に確認したいので、これは潜在的により柔軟で透過的です(妄想と呼んでください)。

何か不足していますか? MainブランチとReleaseブランチでのコードファースト移行を無効にするための設定があると思います(DBがスクリプトによって作成および更新されることを前提としています)。それ以外は安全な解決策のように感じますが、私はセカンドオピニオンを評価します。

0
Liam Weston