ホーム > 未分類 > EntityFramework Coreのマイグレーションのロールバック

EntityFramework Coreのマイグレーションのロールバック


実行環境へのデプロイが失敗した場合、すぐさま解決できるかどうかわからないので、できればいったんリリース前の状態に戻したいのだけれど、データベースのマイグレーションがかかわってくるとだいぶ混乱する。手順としてちゃんとまとめてなかったので個人的にまとめる。

例にする状況

例えば、下記の例はC#側で管理されているマイグレーションがすべて実施された状態のC#ソリューションの状態とデータベースの状態で、最後に実施されたマイグレーションは初期登録(20190822050256_initial)になっている。
1.初期状態-db
1.初期状態

この状態でプログラム側では下記の順にデータベースのマイグレーションが追加されたとする。
– EntityBの追加
– EntityAに対するAddressカラムの追加
– EntityCの追加
2.EntityBの追加とEntityAに対する修正、EntityCを行い、修正スクリプトを追加した

で、例えば手で(Alter Tableなどで)EntityAにAddressカラムが追加されていたとしたら、当然のことながらマイグレーション実行時にAddressカラムがすでに存在するので、次のようなエラーが発生してマイグレーションが失敗する。

エラーメッセージ

この時点のデータベースの状態は下記のようになっている。
EntityBの追加は成功しているけれど、EntityAの修正とEntityCの追加が失敗しているので、履歴としては20190822050515_add_entitybが最新
4.失敗後のデータベースの状態

データベースのダウングレード

マイグレーションのダウングレード手順

マイグレーションをダウングレードする場合、次の手順で作業を行う。
– 現在のマイグレーションの状況を確認する
– マイグレーションの復旧時点を決める
– マイグレーションのダウングレードを行う
– 以前動作していたアプリを再デプロイする

マイグレーションの状況を確認と復旧時点の決定

マイグレーションはデータベース上の __EFMigrationHistory テーブルで管理されている。
マイグレーションに失敗した場合、このテーブルと、C#側で管理しているマイグレーションの履歴を確認しどこまでマイグレーションが実施されたかを確認する。今回は前回正しく動いていたのが20190822050256_initialの状態なので、ここを目指してダウングレードを行う。

コマンドはこんな感じ、あくまで実行されたマイグレーションのDownに定義された操作を実施するだけなので、手動で追加されたカラムはそのままになっている。
dotnet ef database update 20190822050256_initial -p ./Data -s ./WebApplication6

コメント 2019-08-22 142200

dotnet ef コマンドの詳細は下記のページを参照
Entity Framework Core ツールリファレンス-.NET CLI
https://docs.microsoft.com/ja-jp/ef/core/miscellaneous/cli/dotnet

で、後は以前動いていたアプリケーションを動かせばその日の対応は完了。

その後の対応

もちろんこの例の場合は、マイグレーションで管理されているテーブルに対して手動でメンテナンスしたことがそもそもの間違いなので、対象カラムをドロップ後マイグレーションを流しなおすのが正しい。もちろんデータの喪失を防ぐために一時的に添付テーブルにデータを退避後、マイグレーションが成功した後にパッチを当てるなどの対応が必要になる。

ただ、複数人で開発中にEntityをデータコンテキストに追加したままマイグレーションを追加忘れたままPushしてしまい、他の人のマイグレーションに紛れてしまってdevelopマージ後におかしくなる。みたいなケースがあるので、その場合は、誤ったマイグレーションを削除してマイグレーションを追加しなおす必要がる。
その場合は、dotnet migrations removeコマンドで不要なマイグレーションを削除したのち、正しいマイグレーションを追加することになる。

解決していない問題

基本的にはマイグレーションのエラーを起こさないのが一番なので、CI/CDで本番環境にデプロイする前にSTG環境のようなものを作り、マイグレーションの直前に本番データベースの状態をスナップショットからSTG環境を作成しマイグレーションのテストをするのが望ましい気がする。データボリュームとかで難しいかもしれないけれど、、、

実際にデータベースのロールバック時にいつ時点のマイグレーションに戻せばいいのかとか、リリースでてんぱっているときに調べるのはだいぶつらい気がする。回避の案としては、__EFMigrationHistory に対するデータベーストリガーを作っておいて、前回のデプロイ時にどのマイグレーションが走ったのかを管理するとかしておけば、まだどうにかなる気がする。__EFMigrationHistoryテーブルに更新日とか入ってくれないかなー。

カテゴリー:未分類
  1. まだコメントはありません。
  1. No trackbacks yet.

コメントを残す