移行の適用

移行を追加したら、それらを展開し、データベースに適用する必要があります。 これを行うためのさまざまな戦略があります。一部は運用環境に適しており、その他のものは開発ライフサイクルに適しています。

Note

どの展開戦略であっても、必ず、生成された移行を検査およびテストしてから運用データベースに適用するようにしてください。 列の名前変更を意図していたが、移行で列が削除されたり、データベースに適用するときにさまざまな理由で失敗したりする場合があります。

デプロイ戦略を選択する

自動デプロイの場合は、 移行バンドルを使用します。 バンドルは、CI で生成され、.NET SDK、EF Core ツール、またはアプリケーションのソース コードなしで後で実行できるデプロイ成果物です。 SQL を適用する前に、SQL を確認、変更、アーカイブ、または DBA に渡す必要がある場合は、代わりに SQL スクリプト を使用します。

ローカル開発では、通常、 dotnet ef database update または Update-Database が最も簡単なオプションです。 熱望プロジェクトでは、 Ef Core 移行の統合 を使用して、ローカル移行の実行を調整し、バンドルまたはスクリプトを発行する必要があります。

戦略 推奨される使用方法 実行前に SQL を確認する 実行時に SDK とソースが必要 EF 移行ロックを使用する EF シード処理デリゲートを実行します
SQL スクリプト DBA によって制御されるデプロイまたはレビューゲートされたデプロイ Yes No No No
移行バンドル 自動化されたデプロイ No No Yes Yes
EF コマンド ライン ツール ローカルでの開発とテスト No Yes Yes Yes
ランタイムの移行 スタートアップ移行のトレードオフを受け入れるアプリケーション No No Yes Yes

EF Core 9 以降では、移行ロックが使用されます。 同期操作とツール呼び出し UseSeeding。非同期操作は UseAsyncSeedingを呼び出します。

スキーマを変更するアクセス許可を持つデプロイには、別の ID を使用します。 アプリケーションが実行時に使用する ID には、通常、アプリケーションがデータの読み取りと書き込みに必要なアクセス許可のみを持つ必要があります。

SQL スクリプト

SQL スクリプトは、デプロイ プロセスで、生成された SQL を実行前に検査または変更する必要がある場合に推奨されます。 この戦略の利点は次のとおりです。

  • SQL スクリプトの正確性を審査することができます。スキーマ変更を運用データベースに適用することは、データ損失を伴う可能性のある危険な操作であるため、このことは重要です。
  • 場合によっては、運用データベースの特定のニーズに合わせてスクリプトを調整できます。
  • SQL スクリプトは展開テクノロジと組み合わせて使用でき、CI プロセスの一部として生成することもできます。
  • SQL スクリプトは DBA に提供でき、個別に管理およびアーカイブすることもできます。

基本的な使用方法

次の例では、空のデータベースから最新の移行への SQL スクリプトが生成されます。

dotnet ef migrations script

既定では、このコマンドはスクリプトを標準出力に書き込みます。 --output (または-o) を使用して、予測可能な名前のデプロイ 成果物を作成します。

dotnet ef migrations script --idempotent --output artifacts/migrations.sql

From を使用する (暗黙的な指定に対して)

次の例では、特定の移行から最新の移行への SQL スクリプトが生成されます。

dotnet ef migrations script AddNewTables

From および To を使用する

次の例では、指定された from の移行から指定された to の移行への SQL スクリプトが生成されます。

dotnet ef migrations script AddNewTables AddAuditTable

ロールバック スクリプトを生成するために、from より新しい to を使用することができます。

Warning

データ損失の可能性のあるシナリオには注意してください。

スクリプト生成では、生成する必要がある移行の範囲を示す次の 2 つの引数を受け取ります。

  • from 移行は、スクリプトの実行前にデータベースに適用される最後の移行にする必要があります。 移行が適用されていない場合、0 を指定します (これは既定です)。
  • to 移行は、スクリプトの実行後にデータベースに適用される最後の移行です。 これは既定でプロジェクトの最後の移行になります。

移行スクリプトは、既存のデータベースを更新します。 スクリプトを適用する前に、インフラストラクチャのデプロイまたはデータベース管理プロセスを通じてデータベース自体をプロビジョニングします。 通常、データベースの作成には、別の接続、昇格されたアクセス許可、およびプロバイダー固有の構成が必要です。

べき等 SQL スクリプト

上記で生成される SQL スクリプトは、スキーマをある移行から別の移行に変更するためにのみ適用できます。スクリプトを適切に適用し、正しい移行状態のデータベースに対してのみ適用することは、ユーザーの責任です。 EF Core では、べき等スクリプトの生成もサポートしています。これは、既に適用されている移行を (移行履歴テーブルを使用して) 内部的に検査し、不足している移行のみを適用するものです。 これは、データベースに適用された最後の移行が正確にわからない場合、あるいは移行が異なる可能性がある複数のデータベースに展開する場合に便利です。

べき等スクリプトのサポートは、データベース プロバイダーによって異なります。 たとえば、SQLite では現在、べき等移行スクリプトの生成はサポートされていません。

次の例では、べき等移行が生成されます。

dotnet ef migrations script --idempotent

コマンド ライン ツール

EF コマンド ライン ツールを使用して、データベースに移行を適用できます。 このアプローチは移行のローカル開発とテストでは生産性が高いですが、運用データベースの管理には最適ではありません。

  • SQL コマンドがツールによって直接適用され、開発者に検査や変更を行う機会がありません。 これは運用環境では危険な場合があります。
  • .NET SDK と EF ツールは運用サーバーにインストールする必要があり、プロジェクトのソース コードが必要です。

次の例では、データベースを最新の移行に更新します。

dotnet ef database update

次の例では、データベースを特定の移行に更新します。

dotnet ef database update AddNewTables

以前の移行にロールバックするためにも使用できます。

Warning

データ損失の可能性のあるシナリオには注意してください。

コマンド ライン ツールを使用して移行を適用する方法の詳細については、「EF Core ツールのリファレンス」を参照してください。

環境と構成

ツールは、アプリケーション コードを実行して DbContextを構築します。 そのため、プロバイダーの選択、接続文字列、およびモデルの構成は、アプリケーション環境によって異なります。 EF Core のデザイン時ツールでは、ASPNETCORE_ENVIRONMENTDOTNET_ENVIRONMENTも設定されていない場合、Development環境が使用されます。

デプロイ成果物を生成するとき、およびバンドルを実行するときに、環境を明示的に設定します。 たとえば、PowerShell で以下を実行します。

$env:ASPNETCORE_ENVIRONMENT = 'Production'
dotnet ef migrations bundle --output artifacts\efbundle.exe
$env:ASPNETCORE_ENVIRONMENT = 'Production'
.\efbundle.exe --connection $env:DEPLOYMENT_CONNECTION_STRING

または POSIX と互換性のあるシェルの場合:

ASPNETCORE_ENVIRONMENT=Production \
    dotnet ef migrations bundle --output artifacts/efbundle

ASPNETCORE_ENVIRONMENT=Production \
    ./efbundle --connection "$DEPLOYMENT_CONNECTION_STRING"

これにより、バンドルが開発ユーザー シークレットを予期せず読み込めなくなります。 バンドルのより安全な既定の環境は 、dotnet/efcore#36188 によって追跡されます。 Visual Studio発行エクスペリエンスでの環境の選択は、dotnet/efcore#11950 によって追跡されます。

運用環境の接続文字列をソース管理に格納したり、バンドルに埋め込んだりしないでください。 デプロイ システムのシークレット ストアからデプロイ接続を指定します。 デプロイ ID にはスキーマのアクセス許可が必要です。通常、通常のアプリケーション ID では使用しないでください。

Bundles

移行バンドルは、データベースに移行を適用するために使用できる単一ファイルの実行可能ファイルです。 これらは、次のような SQL スクリプトとコマンドライン ツールの欠点の一部に対処します。

  • SQL スクリプトを実行するには、追加のツールが必要です。
  • これらのツールによるトランザクション処理とエラー時の続行動作には一貫性がなく、予期できない場合もあります。 そのため、移行の適用時にエラーが発生した場合に、データベースが未定義の状態になる可能性があります。
  • バンドルは、CI プロセスの一部として生成することができ、後で配置プロセスの一部として簡単に実行することができます。
  • バンドルは、.NET SDK または EF ツール (自己完結型の場合は .NET ランタイム) をインストールせずに実行でき、プロジェクトのソース コードは必要ありません。
  • バンドルでは、EF Core の移行ロックを使用し、構成された UseSeeding ロジックを実行します。

SQL スクリプトとは異なり、バンドルには現在、それが実行する SQL を検査したり、それに含まれる移行を一覧表示したりする方法はありません。 デプロイで SQL レビューが必要な場合は、代わりにスクリプトを生成します。 バンドル検査の機能強化は、 dotnet/efcore#25872 によって追跡されます。

以下により、バンドルが生成されます。

dotnet ef migrations bundle --output artifacts/efbundle

以下により、Linux 用の自己完結型バンドルが生成されます。

dotnet ef migrations bundle --self-contained --target-runtime linux-x64 --output artifacts/efbundle

バンドルの作成の詳細については、「EF Core ツールのリファレンス」を参照してください。

efbundle

生成される実行可能ファイルは、既定では efbundle という名前になります。 これは、データベースを最新の移行に更新するために使用できます。 これは、dotnet ef database update または Update-Database を実行するのと同等です。

Arguments:

Argument Description
<MIGRATION> ターゲット移行。 '0' の場合、すべての移行が元に戻されます。 既定値は、最後の移行です。

Options:

Option Short Description
--connection <CONNECTION> データベースへの接続文字列。 既定値は、AddDbContext または OnConfiguring に指定されたものです。
--verbose -v 詳細出力を表示します。
--no-color 出力を色分けしません。
--prefix-output レベルを付けて出力します。

次の例では、指定したユーザー名と資格情報を使用して、ローカル SQL Server インスタンスに移行を適用します。

.\efbundle.exe --connection 'Data Source=(local)\MSSQLSERVER;Initial Catalog=Blogging;User ID=myUsername;Password={;'$Credential;'here'}'

データベースをロールバックするには、引き続き適用する必要がある移行を渡します。 0渡すと、すべての移行が元に戻ります。

.\efbundle.exe PreviousMigration --connection 'Data Source=(local)\MSSQLSERVER;Initial Catalog=Blogging;Integrated Security=True'
.\efbundle.exe 0 --connection 'Data Source=(local)\MSSQLSERVER;Initial Catalog=Blogging;Integrated Security=True'

Warning

ロールバックでは、ターゲットよりも新しい移行ごとに Down 操作が実行され、データが失われる可能性があります。 運用環境のデータで使用する前に、ロールバックの動作を確認してテストします。

構成されたシード処理コードは、ダウングレード後に実行されます。 ターゲットが 0されている場合は、不足しているアプリケーション スキーマを含め、ターゲット移行のスキーマを許容する必要があります。

Warning

コンテキスト構成が appsettings.json読み取る場合は、バンドルと共に必要な設定ファイルをコピーします。 構成ファイルは、バンドルの実行ディレクトリから解決されます。 これらのファイルに運用シークレットを配置しないでください。セキュリティで保護された構成ソースまたは --connection オプションを使用して提供します。

コンテナーとデプロイ ジョブ

ビルド中にバンドルを生成し、データベースが正常になった後に 1 回限りのデプロイ ジョブとして実行します。 アプリケーション イメージに SDK をインストールしたり、 dotnet ef を実行したりしないでください。また、すべてのアプリケーション レプリカがそのエントリ ポイントから移行を実行するわけではありません。 正常に終了した後に移行コンテナーを再起動しないようにデプロイ プラットフォームを構成します。

アスパイア アプリケーションの場合、 AddEFMigrations はローカル開発時に移行を調整できます。 発行中、 PublishAsMigrationBundle はバンドルまたはコンテナー イメージを出力でき、 PublishAsMigrationScript は SQL スクリプトを出力できます。 Azure Container Apps、Docker Compose、Kubernetes のワンショット ジョブ構成については、アスパイアでの EF Core 移行の適用に関するページを参照してください。

移行バンドルのサンプルでは、2 つの SQLite 移行、べき等シード処理、フォワード アプリケーション、ロールバック セーフ シード処理を示します。

移行バンドルの例

バンドルには、組み込む移行が必要です。 これらは「dotnet ef migrations add」を使用して作成されるもので、Create your first migrationで説明されています。 移行を展開する準備ができたら、dotnet ef migrations bundle を使用してバンドルを作成します。 例えば次が挙げられます。

PS C:\local\AllTogetherNow\SixOh> dotnet ef migrations bundle
Build started...
Build succeeded.
Building bundle...
Done. Migrations Bundle: C:\local\AllTogetherNow\SixOh\efbundle.exe
PS C:\local\AllTogetherNow\SixOh>

出力は、対象のオペレーティング システムに適した実行可能ファイルです。 私の場合、これはx64 Windowsなので、efbundle.exeローカルフォルダにドロップされます。 この実行可能ファイルを実行すると、その中に含まれる移行が適用されます。

PS C:\local\AllTogetherNow\SixOh> .\efbundle.exe
Applying migration '20210903083845_MyMigration'.
Done.
PS C:\local\AllTogetherNow\SixOh>

dotnet ef database updateUpdate-Database と同様に、移行は、まだ適用されていない場合にのみ、データベースに適用されます。 たとえば、同じバンドルを再度実行しても、適用する新しい移行がないため、何も行われません。

PS C:\local\AllTogetherNow\SixOh> .\efbundle.exe
No migrations were applied. The database is already up to date.
Done.
PS C:\local\AllTogetherNow\SixOh>

ただし、モデルを変更し、dotnet ef migrations add を使用してさらに移行を生成した場合は、適用できる状態の新しい実行可能ファイルにそれらをバンドルできます。 例えば次が挙げられます。

PS C:\local\AllTogetherNow\SixOh> dotnet ef migrations add SecondMigration
Build started...
Build succeeded.
Done. To undo this action, use 'ef migrations remove'
PS C:\local\AllTogetherNow\SixOh> dotnet ef migrations add Number3
Build started...
Build succeeded.
Done. To undo this action, use 'ef migrations remove'
PS C:\local\AllTogetherNow\SixOh> dotnet ef migrations bundle --force
Build started...
Build succeeded.
Building bundle...
Done. Migrations Bundle: C:\local\AllTogetherNow\SixOh\efbundle.exe
PS C:\local\AllTogetherNow\SixOh>

Tip

--force オプションを使用すると、既存のバンドルを新しいバンドルで上書きできます。

この新しいバンドルを実行すると、これら 2 つの新しい移行がデータベースに適用されます。

PS C:\local\AllTogetherNow\SixOh> .\efbundle.exe
Applying migration '20210903084526_SecondMigration'.
Applying migration '20210903084538_Number3'.
Done.
PS C:\local\AllTogetherNow\SixOh>

既定では、バンドルはアプリケーションの構成からデータベースの接続文字列を使用します。 ただし、コマンド ラインで接続文字列を渡すことで、別のデータベースを移行できます。 例えば次が挙げられます。

PS C:\local\AllTogetherNow\SixOh> .\efbundle.exe --connection "Data Source=(LocalDb)\MSSQLLocalDB;Database=SixOhProduction"
Applying migration '20210903083845_MyMigration'.
Applying migration '20210903084526_SecondMigration'.
Applying migration '20210903084538_Number3'.
Done.
PS C:\local\AllTogetherNow\SixOh>

Note

ここでは、3 つの移行がすべて適用されました。これは、これらのいずれもまだ、運用データベースに適用されていなかったためです。


実行時に移行を適用する

アプリケーション自体が、通常は起動時にプログラムによって移行を適用することができます。 EF Core 9 以降では、データベース全体のロックを使用して移行の実行が保護されるため、単純なデプロイを優先し、スタートアップ移行の動作を許容できるアプリケーションでこれを許容できます。 レビュー、最小特権の資格情報、調整されたロールアウト、または高可用性が重要な場合は、別の移行デプロイ手順が推奨されます。

次のトレードオフについて考えてみましょう。

  • EF 9より前のバージョンでは、アプリケーションの複数のインスタンスが実行されている場合、両方のアプリケーションが同時に移行を適用しようとして失敗する可能性があります (最悪の場合、データが破損する可能性があります)。
  • 同様に、アプリケーションが移行している間に別のアプリケーションがデータベースにアクセスした場合、重大な問題が発生する可能性があります。
  • アプリケーションに、データベース スキーマを変更するための昇格されたアクセス権が必要です。 一般に、アプリケーションのデータベース アクセス許可を運用環境で制限することが推奨されています。
  • 問題が発生した場合、適用された移行をロールバックできる必要があります。 他の戦略では、これを簡単かつすぐに実行できます。
  • SQL コマンドがプログラムによって直接適用され、開発者に検査や変更を行う機会がありません。 これは運用環境では危険な場合があります。

移行をプログラムで適用するには、context.Database.MigrateAsync() を呼び出します。 たとえば、一般的な ASP.NET アプリケーションでは、次の操作を実行できます。

public static async Task Main(string[] args)
{
    var host = CreateHostBuilder(args).Build();

    using (var scope = host.Services.CreateScope())
    {
        var db = scope.ServiceProvider.GetRequiredService<ApplicationDbContext>();
        await db.Database.MigrateAsync();
    }

    host.Run();
}

MigrateAsync() は、より高度なシナリオで利用される IMigrator サービスの上にビルドされます。 アクセスするには myDbContext.GetInfrastructure().GetService<IMigrator>() を利用します。

Warning

  • このアプローチを運用環境で使用する前に、慎重に検討してください。 レビューと承認が必要な場合は、自動化または SQL スクリプトに移行バンドルを使用します。
  • EnsureCreatedAsync() の前に MigrateAsync() を呼び出さないでください。 EnsureCreatedAsync() は移行をバイパスしてスキーマを作成し、MigrateAsync() が失敗します。

移行時のロック

EF Core 9以降では、MigrateAsyncおよびMigrateが自動的にデータベース全体のロックを取得してから移行を適用します。 これにより、複数のアプリケーション インスタンスが同時に移行を実行することによって発生する可能性があるデータベースの破損から保護されます。これは、 実行時に移行を適用する場合の一般的なシナリオです。 ロックは、 シード処理コードを含め、移行の実行期間中保持され、操作が完了すると自動的に解放されます。

移行ロックは、次のいずれかの方法を使用して移行が適用されるときに適用されます。

SQL スクリプト は EF Core の外部で適用されるため、移行ロックの影響を受けません。

Note

EF Core 9 以降、モデルに前回のマイグレーション以降に変更が保留されている場合、Migrate() または MigrateAsync() を呼び出すと例外が発生します (警告イベント ID RelationalEventId.PendingModelChangesWarning)。 デプロイ前にこの状態を検出するには、CI/CD パイプラインで dotnet ef migrations has-pending-model-changes コマンドを使用します。 警告は、必要に応じて ConfigureWarnings ( RelationalEventId.PendingModelChangesWarningを無視) して抑制できますが、運用環境のシナリオでは一般的には推奨されません。 詳細については、 破壊的変更に関するメモを 参照してください。

Warning

ロック メカニズムはデータベース プロバイダーによって大きく異なり、プロバイダー固有の問題が発生する可能性があります。 たとえば、SQLite プロバイダーは、 プロセスが予期せず終了した場合に破棄される可能性があるロック テーブルを使用します。 詳細については、プロバイダーのドキュメントを常に参照してください。

制限事項