🐈

Entity Framework Coreのマイグレーションを安全に運用するための設計と工夫

に公開

Entity Framework Coreのマイグレーションを安全に運用するための設計と工夫

✅ はじめに

Entity Framework Core(EF Core)のマイグレーション機能は、コードベースでDBスキーマを管理できる便利な仕組みですが、運用を誤ると本番DBの破壊やチーム内の混乱を招きます。この記事では、実際の運用を想定して、EF Coreマイグレーションを安全・確実に運用するための設計と工夫を紹介します。

💣 よくあるマイグレーション事故パターン

1. 本番にdotnet ef database updateが直撃

  • 本番環境でうっかりCLIを実行し、想定外のスキーマ変更が反映される
  • 対応:本番ではSQLをレビューしてから適用を徹底

2. 開発者ごとのスキーマ差異

  • 開発環境のDB構成がバラバラで、マイグレーションに齟齬が出る
  • 対応:明示的なローカル初期化とマイグレーション適用フローの整備

3. マージでマイグレーションが衝突

  • 同時期に複数人がマイグレーションを追加し、順序が競合
  • 対応:マイグレーション命名とPR内レビューの徹底

🧱 設計とルールで防ぐ

1. 命名規則

20240517_AddUserStatusColumn.cs
  • 作成日+機能内容で命名(競合しにくく、変更履歴も把握しやすい)

2. ステージングでの差分確認

  • dotnet ef migrations scriptで生成したSQLをステージングDBに適用し、影響範囲を確認

3. マイグレーションのレビュー文化

  • PRで必ずマイグレーションSQLをコメントとして貼付
  • ex. dotnet ef migrations script 20240510 20240517

4. 本番ではマイグレーションSQLを明示適用

  • CIで出力されたSQLを手動またはスクリプトで適用
  • DbContext.Database.Migrate()本番では使用禁止(開発・テスト用)

🛠️ CI/CDパイプラインの工夫

パイプライン上での基本的な流れ

  1. マイグレーションファイルが追加されたことを検出
  2. dotnet ef migrations script で差分SQLを生成
  3. 差分SQLを成果物(artifact)として保存
  4. Pull RequestにSQLを自動コメント
  5. (任意)ステージング環境に自動適用して検証

🔄 自動でマイグレーション範囲を検出する方法

EF Coreの dotnet ef migrations script は、以下のように 開始マイグレーション名と終了マイグレーション名 を指定できます:

# 差分のSQLを生成
# 例:20240510 から 20240517 の差分を出力

dotnet ef migrations script 20240510 20240517 --output migration.sql

しかし、これを毎回手動で書くのは面倒です。CI上では次のように自動で最後に適用されたマイグレーションと最新のマイグレーションを検出し、その範囲を用いてスクリプトを生成する運用が有効です。

__EFMigrationsHistory の活用

EF Core では、マイグレーションの適用履歴を自動的に追跡するためのテーブル __EFMigrationsHistory が作成されます。このテーブルには、過去に適用されたマイグレーションの一覧が格納されており、前回適用済みのマイグレーション名を正確に取得することができます。

__EFMigrationsHistory の構造(例)

MigrationId ProductVersion
20240510_AddEmailToUsers 8.0.4
20240517_AddStatusToUsers 8.0.4

利用方法(SQL)

SELECT MigrationId
FROM __EFMigrationsHistory
ORDER BY MigrationId DESC
LIMIT 1;

CI/CD パイプラインでこの情報を DB から取得し、dotnet ef migrations scriptfromMigration として使うことができます。

スクリプト例(psql を使った取得)

# PostgreSQL例
export FROM_MIGRATION=$(psql "$CONNECTION_STRING" -t -c "SELECT MigrationId FROM __EFMigrationsHistory ORDER BY MigrationId DESC LIMIT 1;" | xargs)
export TO_MIGRATION=$(dotnet ef migrations list | grep '^[[:space:]]*[0-9]' | tail -n 1 | xargs)

dotnet ef migrations script $FROM_MIGRATION $TO_MIGRATION --output ./artifacts/migration.sql

運用上の利点

  • previous_migration.txt の手動更新不要
  • 本番DBの実際の状態に基づいてスクリプトを生成
  • 適用漏れやずれを防げる

__EFMigrationsHistory はすべての EF Core プロジェクトで自動生成され、マイグレーションの正確なトラッキングに利用可能です。

GitHub Actionsで更新する例(mainマージ時)

GitHub Actions の例

      - name: Generate SQL script from EF Core
        run: |
          from=$(sqlcmd -S your-sqlserver -d your-db -U your-user -P your-password -Q "SET NOCOUNT ON; SELECT TOP 1 [MigrationId] FROM [__EFMigrationsHistory] ORDER BY [MigrationId] DESC" -h -1 -W)
          to=$(dotnet ef migrations list | grep '^[[:space:]]*[0-9]' | tail -n 1 | xargs)
          dotnet ef migrations script $from $to --output ./artifacts/migration.sql

PRへの自動コメント例

PRコメントに以下のように表示:

### 🔍 EFマイグレーション差分SQL
```sql
ALTER TABLE Users ADD COLUMN Status INT NOT NULL DEFAULT 0;
...

### ステージング検証の組み込み(オプション)
- ステージングDBに対して差分SQLを適用
- 結果に応じてSlack通知やGitHubチェックを返す

### 本番環境への反映
- 出力された `migration.sql` をレビュー・承認後に、DBAまたはデプロイスクリプトで手動適用
- 適用ログは必ず保存して監査対応にも備える

## 🧪 テスト環境でのリハーサル

### ローカルでの検証手順
```bash
# 一度DBを削除
dotnet ef database drop -f
# 最新マイグレーションを適用
dotnet ef database update
  • すべてのマイグレーションが連続して正しく適用できることを保証

自動検証

  • CIで空のSQLite DBにマイグレーション適用して検証
  • 実スキーマとの差分を検出するツール導入(EF Power Tools など)

🧭 応用Tips

マイグレーションのマージ

  • 衝突時は Remove-Migration + Add-Migration で統合
  • Gitのリベースと一緒に調整することできれいな履歴に

モデルの変更検知

  • 差分があるのにマイグレーションを忘れた場合、CIで警告を出す
  • 例:dotnet ef migrations add DummyCheckで差分検知用のダミーを作る

📚 まとめ

  • EF Coreのマイグレーションは便利だが、運用設計が命
  • 本番では自動適用せず、SQLレビューと手動適用を原則とする
  • チーム内のルールと自動化によって、事故を防ぎつつ効率的に運用可能

Discussion