次の方法で共有


Movie モデルとテーブルに新しいフィールドを追加する

作成者: Rick Anderson

Note

ASP.NET MVC 5 と Visual Studio 2013 を使用するこのチュートリアルの更新版は、こちらで入手できます。 より安全で、より簡単に操作でき、より多くの機能を備えています。

このセクションでは、Entity Framework Code First Migrations を使用してモデル クラスにいくつかの変更を移行し、変更がデータベースに適用されるようにします。

このチュートリアルの前の方でしたように、Entity Framework の Code First を使用してデータベースを自動作成すると、既定で Code First がテーブルをデータベースに追加して、データベースのスキーマがその生成元であるモデル クラスと同期されているかを追跡するようになります。 もし同期されていない場合、Entity Framework はエラーをスローします。 これにより、実行時にあいまいなエラーが表示されて初めて気づくような問題を、開発段階で容易に追跡できるようになります。

モデル変更用の Code First Migrations の設定

Visual Studio 2012 を使用している場合は、ソリューション エクスプローラーから Movies.mdf ファイルをダブルクリックしてデータベース ツールを開きます。 Visual Studio Express for Web にはデータベース エクスプローラーが表示され、Visual Studio 2012 にはサーバー エクスプローラーが表示されます。 Visual Studio 2010 を使用している場合は、SQL Server オブジェクト エクスプローラーを使用します。

データベース ツール (データベース エクスプローラー、サーバー エクスプローラー、SQL Server オブジェクト エクスプローラー) で [MovieDBContext] を右クリックし、[削除] を選択してムービー データベースを削除します。

Screenshot that shows the Server Explorer window. Delete is selected in the Movie D B Context right click menu.

ソリューション エクスプローラーに戻ります。 Movies.mdf ファイルを右クリックし、[削除] を選択してムービー データベースを削除します。

Screenshot that shows the Solution Explorer window. Delete is selected in the Movies dot m d f right click menu.

アプリケーションをビルドしてエラーがないことを確認します。

[ツール] メニューで [NuGet パッケージ マネージャー][パッケージ マネージャー コンソール] の順にクリックします。

Add Pack Man

パッケージ マネージャー コンソール ウィンドウの PM> プロンプトで、「Enable-Migrations -ContextTypeName MvcMovie.Models.MovieDBContext」と入力します。

Screenshot that shows the Package Manager Console window. The Enable Migrations command is entered.

Enable-Migrations コマンド (上記) は、新しい Migrations フォルダーに Configuration.cs ファイルを作成します。

Screenshot that shows the Solution Explorer window. The Migrations folder and Configuration dot c s file are circled in red.

Visual Studio によって Configuration.cs ファイルが開かれます。 Configuration.cs ファイル内の Seed メソッドを次のコードに置き換えます。

protected override void Seed(MvcMovie.Models.MovieDBContext context)
{
    context.Movies.AddOrUpdate( i => i.Title,
        new Movie
        {
            Title = "When Harry Met Sally",
            ReleaseDate = DateTime.Parse("1989-1-11"),
            Genre = "Romantic Comedy",
            Price = 7.99M
        },

         new Movie
         {
             Title = "Ghostbusters ",
             ReleaseDate = DateTime.Parse("1984-3-13"),
             Genre = "Comedy",
             Price = 8.99M
         },

         new Movie
         {
             Title = "Ghostbusters 2",
             ReleaseDate = DateTime.Parse("1986-2-23"),
             Genre = "Comedy",
             Price = 9.99M
         },

       new Movie
       {
           Title = "Rio Bravo",
           ReleaseDate = DateTime.Parse("1959-4-15"),
           Genre = "Western",
           Price = 3.99M
       }
   );
   
}

Movie の下の赤い波線を右クリックし、[解決][usingMvcMovie.Models] の順に選択します。

Screenshot that shows Resolve selected in the Movie right click menu.

これにより、次の using ステートメントが追加されます。

using MvcMovie.Models;

Note

Code First Migrations は、移行が終わるたびに Seed メソッドを呼び出し (つまり、パッケージ マネージャー コンソールで update-database を呼び出す)、このメソッドは既に挿入されている行を更新するか、まだ存在しない場合は挿入します。

Ctrl + Shift + B キーを押して、プロジェクトをビルドします。(この時点でビルドしないと、次の手順は失敗します)

次の手順では、最初の移行用の DbMigration クラスを作成します。 この移行により、新しいデータベースが作成されます。そのため、前の手順で movie.mdf ファイルを削除しました。

パッケージ マネージャー コンソール ウィンドウで、"add-migration Initial" コマンドを入力して最初の移行を作成します。 "Initial" という名前は任意です。作成される移行ファイルに名前を付けるために使用します。

Screenshot that shows the Package Manager Console window. The paragraph that begins with The Designer Code for this migration file is highlighted.

Code First Migrations は Migrations フォルダー ({DateStamp}_Initial.cs という名前で) に別のクラス ファイルを作成します。このクラスにはデータベース スキーマを作成するコードが含まれています。 移行のファイル名の先頭には、並べ替えに役立つタイムスタンプが付きます。 {DateStamp}_Initial.cs ファイルを調べます。これには、Movie DB の Movies テーブルを作成する手順が含まれています。 次の手順でデータベースを更新すると、この {DateStamp}_Initial.cs ファイルが実行され、DB スキーマが作成されます。 次に、Seed メソッドが実行され、テスト データが DB に設定されます。

パッケージ マネージャー コンソールで、"update-database" コマンドを入力してデータベースを作成し、Seed メソッドを実行します。

Screenshot that shows the Package Manager Console window. The update database command is entered.

テーブルが既に存在し、作成できないことを示すエラーが発生した場合は、データベースを削除した後で、update-database を実行する前にアプリケーションを実行したためである可能性があります。 その場合は Movies.mdf ファイルをもう一度削除し、update-database コマンドを再試行してください。 それでもエラーが発生する場合は、移行フォルダーとコンテンツを削除し、このページの上部にある手順から始めます (つまり、Movies.mdf ファイルを削除してから Enable-Migrations に進みます)。

アプリケーションを実行し、/Movies URL に移動します。 シード データが表示されます。

Screenshot that shows the M V C Movie Index page with a list of four movies.

ムービー モデルへの評価プロパティの追加

まず、新しい Rating プロパティを既存の Movie クラスに追加します。 Models\Movie.cs ファイルを開き、次のように Rating プロパティを追加します。

public string Rating { get; set; }

完成した Movie クラスは次のコードのようになります。

public class Movie
{
    public int ID { get; set; }
    public string Title { get; set; }
    public DateTime ReleaseDate { get; set; }
    public string Genre { get; set; }
    public decimal Price { get; set; }
    public string Rating { get; set; }
}

[ビルド]>[ムービーのビルド] メニュー コマンドを使用するか、Ctrl + Shift + B キーを押して、アプリケーションをビルドします。

Model クラスを更新したので、ブラウザー ビューに新しい Rating プロパティを表示するために、\Views\Movies\Index.cshtml および \Views\Movies\Create.cshtml ビュー テンプレートも更新する必要があります。

\Views\Movies\Index.cshtml ファイルを開き、<th>Rating</th> 列見出しを Price 列の直後に追加します。 次に、@item.Rating 値をレンダリングするために、テンプレートの末尾付近に <td> 列を追加します。 更新した Index.cshtml ビュー テンプレートは次のようになります。

@model IEnumerable<MvcMovie.Models.Movie>

@{
    ViewBag.Title = "Index";
}

<h2>Index</h2>

<p>
    @Html.ActionLink("Create New", "Create")
</p>
<table>
    <tr>
        <th>
            @Html.DisplayNameFor(model => model.Title)
        </th>
        <th>
            @Html.DisplayNameFor(model => model.ReleaseDate)
        </th>
        <th>
            @Html.DisplayNameFor(model => model.Genre)
        </th>
        <th>
            @Html.DisplayNameFor(model => model.Price)
        </th>
         <th>
            @Html.DisplayNameFor(model => model.Rating)
        </th>
        <th></th>
    </tr>

@foreach (var item in Model) {
    <tr>
        <td>
            @Html.DisplayFor(modelItem => item.Title)
        </td>
        <td>
            @Html.DisplayFor(modelItem => item.ReleaseDate)
        </td>
        <td>
            @Html.DisplayFor(modelItem => item.Genre)
        </td>
        <td>
            @Html.DisplayFor(modelItem => item.Price)
        </td>
        <td>
            @Html.DisplayFor(modelItem => item.Rating)
        </td>
        <td>
            @Html.ActionLink("Edit", "Edit", new { id=item.ID }) |
            @Html.ActionLink("Details", "Details", new { id=item.ID }) |
            @Html.ActionLink("Delete", "Delete", new { id=item.ID })
        </td>
    </tr>
}

</table>

次に、\Views\Movies\Create.cshtml ファイルを開き、フォームの末尾付近に次のマークアップを追加します。 これによってテキスト ボックスがレンダリングされ、新しいムービーが作成されたときに評価を指定できるようになります。

<div class="editor-label">
    @Html.LabelFor(model => model.Rating)
</div>
<div class="editor-field">
    @Html.EditorFor(model => model.Rating)
    @Html.ValidationMessageFor(model => model.Rating)
</div>

アプリケーション コードを、新しい Rating プロパティをサポートするように更新しました。

ここで、アプリケーションを実行し、/Movies URL にアクセスします。 ただし、アクセスすると次のエラーのいずれかが表示されます。

Screenshot that shows the error Invalid Operation Exception was unhandled by user code.

Screenshot that shows the browser window with an error that states Server Error in Application.

このエラーが表示されるのは、更新された Movie モデル クラスが既存のデータベースの Movie テーブルのスキーマと異なるためです。 (データベース テーブルに Rating 列はありません)。

このエラーを解決するための手法がいくつかあります。

  1. Entity Framework に、新しいモデル クラス スキーマに基づいてデータベースを自動的にドロップさせ、再作成させます。 この方法では、モデルとデータベース スキーマの両方を迅速に改善できるため、テスト用データベースでアクティブに開発を行っている場合に非常に便利です。 ただし欠点もあり、データベースの既存データが失われます。実稼働データベースではこの手法は推奨されません。 初期化子を利用し、データベースにテスト データを自動的に初期投入します。多くの場合、アプリケーション開発の手法として有益な方法です。 Entity Framework データベース初期化子の詳細については、Tom Dykstra の ASP.NET MVC/Entity Framework チュートリアルを参照してください。
  2. モデル クラスに一致するように、既存のデータベースのスキーマを明示的に変更します。 この手法の長所は、データが維持されることです。 この変更は手動で行うことも、データベース変更スクリプトを作成して行うこともできます。
  3. Code First Migrations を使用して、データベース スキーマを更新します。

このチュートリアルでは、Code First Migrations を利用します。

新しい列に値を提供するように、Seed メソッドを更新します。 Migrations\Configuration.cs ファイルを開き、各 Movie オブジェクトに Rating フィールドを追加します。

new Movie
{
    Title = "When Harry Met Sally",
    ReleaseDate = DateTime.Parse("1989-1-11"),
    Genre = "Romantic Comedy",
    Rating = "G",
    Price = 7.99M
},

ソリューションをビルドした後、[パッケージ マネージャー コンソール] ウィンドウを開き、次のコマンドを入力します。

add-migration AddRatingMig

add-migration コマンドは、現在のムービー DB スキーマを使用して現在のムービー モデルを調べ、新しいモデルに DB を移行するために必要なコードを作成するように移行フレームワークに指示します。 "AddRatingMig" という名前は任意です。移行ファイルに名前を付けるために利用されます。 移行ステップにはわかりやすい名前を使用すると便利です。

このコマンドが完了すると、Visual Studio は新しい DbMigration 派生クラスを定義するクラス ファイルを開き、Up メソッドで新しい列を作成するコードを確認できます。

public partial class AddRatingMig : DbMigration
{
    public override void Up()
    {
        AddColumn("dbo.Movies", "Rating", c => c.String());
    }
    
    public override void Down()
    {
        DropColumn("dbo.Movies", "Rating");
    }
}

ソリューションをビルドし、パッケージ マネージャー コンソール ウィンドウで "update-database" コマンドを入力します。

次の図は、パッケージ マネージャー コンソール ウィンドウの出力を示しています (AddRatingMig の前の日付スタンプは異なります)。

Screenshot that shows the update database command.

アプリケーションを再実行し、/Movies の URL に移動します。 新しい [Rating] フィールドが表示されます。

Screenshot that shows the M V C Movie Index page with four movies listed.

[Create New] リンクをクリックして、新しい映画を追加します。 評価も追加できます。

7_CreateRioII

Create をクリックしてください。 評価を含む新しいムービーが、ムービー一覧に表示されます。

7_ourNewMovie_SM

また、Edit、Details、SearchIndex ビュー テンプレートに Rating フィールドを追加する必要があります。

パッケージ マネージャー コンソール ウィンドウに "update-database" コマンドをもう一度入力しても、スキーマがモデルと一致するため、変更は行われません。

このセクションでは、モデル オブジェクトを変更し、データベースをその変更に合わせて同期させる方法を学びました。 また、新しく作成されたデータベースにサンプル データを入力してシナリオを試してみる方法についても学習しました。 次に、モデル クラスに高度な検証ロジックを追加して、ビジネス ルールを適用できるようにする方法を学びましょう。