既存のデータベースに Code First Migrations を使用する
Note
EF4.3 以降のみ - このページで説明する機能や API などは、Entity Framework 4.1 で導入されました。 以前のバージョンを使用している場合、一部またはすべての情報は適用されません。
この記事では、Entity Framework で作成されていない既存のデータベースに Code First Migrations を使用する方法について説明します。
Note
この記事は、読者が基本的なシナリオでの Code First Migrations の使用方法を理解していると想定しています。 それ以外の方は、先に「Code First Migrations」をお読みください。
手順 1 - モデルを作成する
最初の手順で、既存のデータベースを対象とする Code First モデルを作成します。 これを行う方法の詳細なガイダンスについては、「既存のデータベースの Code First」トピックを参照してください。
Note
データベース スキーマの変更が必要になる変更をモデルに加える前に、このトピックの残りの手順に従うことが重要です。 以降の手順では、モデルがデータベース スキーマと同期している必要があります。
手順 2: 移行を有効にする
次の手順で、移行を有効にします。 これを行うには、パッケージ マネージャー コンソールで Enable-Migrations コマンドを実行します。
このコマンドを実行すると、ソリューションに Migrations という名前のフォルダーが作成され、その中に Configuration という名前の 1 つのクラスが格納されます。 Configuration クラスに、アプリケーションの移行を構成します。詳細については、「Code First Migrations」トピックを参照してください。
手順 3: 最初の移行を追加する
移行が作成され、ローカル データベースに適用されたら、これらの変更を他のデータベースに適用したい場合があります。 たとえば、ご自分のローカル データベースをテスト データベースにして、最終的に実稼働データベースや他の開発者のテスト データベースにも変更を適用したい場合があります。 この手順には 2 つのオプションがあり、選択すべきオプションは、他のすべてのデータベースのスキーマが、空であるか、ローカル データベースのスキーマと現在一致しているかどうかによって決まります。
- オプション 1: 既存のスキーマを開始点として使用する。 この方法は、移行が将来適用される他のデータベースとローカル データベースのスキーマが現在同じである場合に使用する必要があります。 たとえば、ローカルのテスト データベースが実稼働データベースの v1 と現在一致していて、後でこれらの移行を適用して実稼働データベースを v2 に更新する場合に使用できます。
- オプション 2: 空のデータベースを開始点として使用する。 この方法は、移行が将来適用される他のデータベースが空の場合 (または、まだ存在しない場合) に使用する必要があります。 たとえば、アプリケーションの開発をテスト データベースを使用して開始したが、移行は使用せず、後で実稼働データベースをゼロから作成する場合に使用できます。
オプション 1: 既存のスキーマを開始点として使用する
Code First Migrations で、最新の移行に格納されているモデルのスナップショットを使用してモデルの変更を検出します (詳細については、「チーム環境での Code First Migrations」を参照してください)。 データベースに現在のモデルのスキーマが既にあると想定するため、空の (何もしない) 移行を生成し、現在のモデルをスナップショットにします。
- パッケージ マネージャー コンソールで Add-Migration InitialCreate –IgnoreChanges コマンドを実行します。 これにより、空の移行が作成され、現在のモデルをスナップショットにします。
- パッケージ マネージャー コンソールで Update-Database コマンドを実行します。 これにより、InitialCreate 移行がデータベースに適用されます。 実際の移行には変更が含まれないため、この移行が既に適用されていることを示す行が __MigrationsHistory テーブルに追加されるだけです。
オプション 2: 空のデータベースを開始点として使用する
このシナリオでは、Migrations で、ローカル データベースに既に存在するテーブルを含め、データベース全体をゼロから作成できる必要があります。 既存のスキーマを作成するロジックを含む InitialCreate 移行を生成します。 次に、既存のデータベースを、この移行が既に適用されているように見せます。
- パッケージ マネージャー コンソールで Add-Migration InitialCreate コマンドを実行します。 これにより、既存のスキーマを作成する移行が作成されます。
- 新しく作成された移行の Up メソッドのコードをすべてコメント アウトします。 これにより、既に存在するすべてのテーブルなどの再作成は試行されず、ローカル データベースに移行を "適用" できるようになります。
- パッケージ マネージャー コンソールで Update-Database コマンドを実行します。 これにより、InitialCreate 移行がデータベースに適用されます。 実際の移行には変更が含まれないため (一時的にコメント アウトしているため)、この移行が既に適用されていることを示す行が __MigrationsHistory テーブルに追加されるだけです。
- Up メソッドのコードのコメントアウトを外します。 これは、この移行が将来のデータベースに適用されるときに、ローカル データベースに既に存在していたスキーマが移行によって作成されることを意味します。
注意事項
既存のデータベースに対して Migrations を使用する場合、注意事項がいくつかあります。
既定または計算される名前が、既存のスキーマと一致しない場合がある
Migrations では、移行をスキャフォールディングするときに列とテーブルの名前を明示的に指定します。 ところが、移行を適用するときに既定の名前が Migrations によって計算される他のデータベース オブジェクトがあります。 これには、インデックスと外部キー制約が含まれます。 既存のスキーマを対象とする場合、計算されるこれらの名前が、データベースに実際に存在する名前と一致しない場合があります。
次に、これに注意する必要がある場合の例をいくつか示します。
手順 3 で「オプション 1: 既存のスキーマを開始点として使用する」を使用した場合:
- モデルの将来の変更で、名前が異なるデータベース オブジェクトの 1 つを変更または削除する必要がある場合は、スキャフォールディングされる移行を変更して正しい名前を指定する必要があります。 Migrations API には、これを実行できる Name パラメーター (オプション) があります。 たとえば、既存のスキーマの Post テーブルに BlogId 外部キー列があり、このインデックスの名前が IndexFk_BlogId であるとします。 ところが、既定で、Migrations により、このインデックスの名前が IX_BlogId であると想定されます。 モデルを変更し、その結果、このインデックスが削除される場合は、スキャフォールディングされる DropIndex 呼び出しを IndexFk_BlogId 名を指定するように変更する必要があります。
手順 3 で「オプション 2: 空のデータベースを開始点として使用する」を使用した場合:
- ローカル データベースに対して最初の移行の Down メソッドを実行しようとする (つまり、空のデータベースに戻す) と、Migrations により、正しくない名前を使用してインデックスと外部キー制約の削除が試行されるため、失敗する可能性があります。 他のデータベースは、最初の移行の Up メソッドを使用してゼロから作成されるため、これはローカル データベースにのみ影響します。 既存のローカル データベースを空の状態にダウングレードする場合は、データベースを削除する、またはすべてのテーブルを削除する処理のいずれかを手動で行うのが最も簡単です。 この最初のダウングレードの後、すべてのデータベース オブジェクトが既定の名前で再作成されます。そのため、この問題自体が再度生じることはありません。
- モデルの将来の変更で、名前が異なるデータベース オブジェクトの 1 つを変更または削除する必要がある場合、名前が既定値と一致しないため、既存のローカル データベースでは機能しません。 一方、"ゼロから" 作成されたデータベースでは、Migrations によって選択される既定の名前が使用されるため、機能します。 これらの変更は、ローカルの既存のデータベースで手動で行うか、他のコンピューターの場合と同様に、Migrations でデータベースをゼロから再作成することを検討できます。
- 最初の移行の Up メソッドを使用して作成されたデータベースは、インデックスと外部キー制約に対して計算された既定の名前が使用されるので、ローカル データベースとは若干異なる場合があります。 既定では、Migrations によって外部キー列にインデックスが作成されるので、追加のインデックスが作成されることもあります。これは、元のローカル データベースではそうはなっていない可能性があります。
すべてのデータベース オブジェクトがモデルで表されるわけではない
モデルに含まれないデータベース オブジェクトは、Migrations では処理されません。 これには、ビュー、ストアド プロシージャ、権限、モデルに含まれないテーブル、追加インデックスなどがあります。
次に、これに注意する必要がある場合の例をいくつか示します。
- 「手順 3」で選択したオプションに関係なく、モデルの将来の変更でこれらの追加オブジェクトを変更または削除する必要があっても、これらの変更は、Migrations によって認識されません。 たとえば、追加インデックスがある列を削除しても、インデックスの削除は、Migrations によって認識されません。 これは、スキャフォールディングされる移行に手動で追加する必要があります。
- 「オプション 2: 空のデータベースを開始点として使用する」を使用した場合、これらの追加オブジェクトは最初の移行の Up メソッドによって作成されません。 必要に応じて、これらの追加オブジェクトを処理するように Up および Down メソッドを変更できます。 Migrations API でネイティブにサポートされていないオブジェクト (ビューなど) の場合は、Sql メソッドを使用して生の SQL を実行して作成/削除できます。
.NET