Share via


新しいフィールドの追加

作成者 : Rick Anderson

Note

このチュートリアルの更新バージョンは、Visual Studio の最新バージョンを使用してこちらで入手できます。 新しいチュートリアルでは、mvc ASP.NET Coreを使用します。これにより、このチュートリアルに対して多くの機能強化が提供されます。

このチュートリアルでは、ASP.NET Core MVC のコントローラーとビューについて説明します。 Razor Pages は、ASP.NET Coreの新しい代替手段であり、Web UI の構築を容易かつ生産的にするページ ベースのプログラミング モデルです。 MVC バージョンの前に Razor Pages チュートリアルを試してみることをお勧めします。 この Razor ページのチュートリアルの特徴は次のとおりです。

  • 使いやすい。
  • 多くの機能をカバーしている。
  • 新しいアプリ開発に推奨されるアプローチです。

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

既定では、このチュートリアルで前述したように、Entity Framework Code First を使用してデータベースを自動的に作成すると、Code First はデータベースにテーブルを追加して、データベースのスキーマが生成元のモデル クラスと同期しているかどうかを追跡するのに役立ちます。 同期されていない場合、Entity Framework はエラーをスローします。 これにより、開発時の問題を簡単に追跡できます。そうしないと、実行時にのみ見つかる可能性がある (あいまいなエラーによって) 可能性があります。

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

[ソリューション エクスプローラー] に移動します。 Movies.mdf ファイルを右クリックし、[削除] を選択して movies データベースを削除しますMovies.mdf ファイルが表示されない場合は、赤いアウトラインで下に示す [すべてのファイルを表示] アイコンをクリックします。

Movies Controller のドット cs タブと開ソリューション エクスプローラーを示すスクリーンショット。[すべてのファイルを表示] アイコンは赤で囲まれています。

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

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

パックマンの追加

プロンプトの [ パッケージ マネージャー コンソール ] ウィンドウで、「 PM> 」と入力します。

Enable-Migrations -ContextTypeName MvcMovie.Models.MovieDBContext

[パッケージ マネージャー コンソール] ウィンドウを示すスクリーンショット。[移行を有効にする] コマンドのテキストが強調表示されています。

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

ソリューション エクスプローラーを示すスクリーンショット。Migrations フォルダーの構成ドット c s サブフォルダーが選択されています。

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

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の赤い波線の上にマウス ポインターを合わせ、[Show Potential FixesMvcMovie.Models の使用] をクリックします。

[潜在的な修正プログラムの表示] メニューを示すスクリーンショット。[Using M V C Movie]\(M V C ムービーの使用\) ドット モデルが選択され、見つからないアラートが表示されます。

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

using MvcMovie.Models;

Note

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

次のコードの AddOrUpdate メソッドは、"upsert" 操作を実行します。

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

Seed メソッドは移行ごとに実行されるため、追加しようとしている行は、データベースを作成する最初の移行の後に既に存在するため、データを挿入することはできません。 "upsert" 操作では、既に存在する行を挿入しようとした場合に発生するエラーは回避されますが、アプリケーションのテスト中に行った可能性のあるデータに対する変更はオーバーライドされます。 一部のテーブルのテスト データでは、そのようなことが起こらない可能性があります。テスト中にデータを変更する場合は、データベースの更新後も変更を残しておく必要があります。 その場合は、条件付き挿入操作を実行します。行がまだ存在しない場合にのみ行を挿入します。

AddOrUpdate メソッドに渡される最初のパラメーターは、行が既に存在する場合にチェックするために使用するプロパティを指定します。 指定するテスト ムービー データでは、リスト内の Title 各タイトルが一意であるため、 プロパティをこの目的に使用できます。

context.Movies.AddOrUpdate(i => i.Title,

このコードでは、タイトルが一意であることを前提としています。 重複するタイトルを手動で追加すると、次に移行を実行するときに次の例外が発生します。

シーケンスに複数の要素が含まれている

AddOrUpdate メソッドの詳細については、「EF 4.3 AddOrUpdate メソッドに注意する」を参照してください。

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

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

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

パッケージ マネージャー コンソールを示すスクリーンショット。[移行の追加] コマンドのテキストが強調表示されています。

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

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

パッケージ マネージャー コンソールを示すスクリーンショット。[データベースの更新] コマンドがウィンドウに表示されます。

テーブルが既に存在し、作成できないことを示すエラーが発生する場合は、データベースを削除した後、および を実行する前にアプリケーションを実行したため update-databaseである可能性があります。 その場合は、 Movies.mdf ファイルをもう一度削除し、コマンドを update-database 再試行します。 それでもエラーが発生する場合は、migrations フォルダーとコンテンツを削除し、このページの上部にある手順から開始します (つまり、 Movies.mdf ファイルを削除してから、Enable-Migrations に進みます)。 それでもエラーが発生する場合は、SQL Server オブジェクト エクスプローラー開き、一覧からデータベースを削除します。 ".mdf ファイルをデータベースとしてアタッチできません" というエラーが表示された場合は、 web.config ファイルの接続文字列の一部として Initial Catalog プロパティを削除します。

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

4 つの映画が一覧表示されている M V C ムービー インデックスを示すスクリーンショット。

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

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

public string Rating { get; set; }

これで、完全な Movie クラスは次のコードのようになります。

public class Movie
{
    public int ID { get; set; }
    public string Title { get; set; }

    [Display(Name = "Release Date")]
    [DataType(DataType.Date)]
    [DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]
    public DateTime ReleaseDate { get; set; }
    public string Genre { get; set; }
    public decimal Price { get; set; }
    public string Rating { get; set; }
}

アプリケーションをビルドします (Ctrl + Shift + B)。

クラスに新しいフィールドを Movie 追加したので、この新しいプロパティが含まれるようにバインド 許可リスト も更新する必要があります。 および アクション メソッドの bindCreateEdit 属性を更新して、 プロパティを Rating 含めます。

[Bind(Include = "ID,Title,ReleaseDate,Genre,Price,Rating")]

ブラウザー ビューで新しい Rating プロパティを表示、作成、編集する目的でビュー テンプレートを更新する必要もあります。

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

@model IEnumerable<MvcMovie.Models.Movie>
@{
    ViewBag.Title = "Index";
}
<h2>Index</h2>
<p>
    @Html.ActionLink("Create New", "Create")
    @using (Html.BeginForm("Index", "Movies", FormMethod.Get))
    {
    <p>
        Genre: @Html.DropDownList("movieGenre", "All")
        Title: @Html.TextBox("SearchString")
        <input type="submit" value="Filter" />
    </p>
    }
</p>
<table class="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 ファイルを Rating 開き、次の強調表示されたマークアップを含むフィールドを追加します。 これにより、テキスト ボックスがレンダリングされ、新しいムービーの作成時に評価を指定できるようになります。

<div class="form-group">
            @Html.LabelFor(model => model.Price, new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.Price, new { htmlAttributes = new { @class = "form-control" } })
                @Html.ValidationMessageFor(model => model.Price, "", new { @class = "text-danger" })
            </div>
        </div>

        <div class="form-group">
            @Html.LabelFor(model => model.Rating, new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.Rating, new { htmlAttributes = new { @class = "form-control" } })
                @Html.ValidationMessageFor(model => model.Rating, "", new { @class = "text-danger" })
            </div>
        </div>

        <div class="form-group">
            <div class="col-md-offset-2 col-md-10">
                <input type="submit" value="Create" class="btn btn-default" />
            </div>
        </div>
    </div>
}

<div>
    @Html.ActionLink("Back to List", "Index")
</div>

@section Scripts {
    @Scripts.Render("~/bundles/jqueryval")
}

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

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

例外ユーザーのハンドルされないエラーを示すスクリーンショット。

"MovieDBContext" コンテキストをサポートするモデルは、データベースの作成以降に変更されています。 Code First Migrations を使用したデータベースの更新を検討してください (https://go.microsoft.com/fwlink/?LinkId=238269)。

アプリケーションの通知サーバー エラーが表示されたブラウザーを示すスクリーンショット。

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

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

  1. Entity Framework に、新しいモデル クラス スキーマに基づいてデータベースを自動的にドロップさせ、再作成させます。 この手法は、開発周期の早い段階で、テスト データベースで開発しているときに非常に便利です。モデルとデータベース スキーマを一緒に短期間で発展させることができます。 ただし、欠点は、データベース内の既存のデータを失うので、運用データベースではこの方法を使用 したくない ということです。 初期化子を利用し、データベースにテスト データを自動的に初期投入します。多くの場合、アプリケーション開発の手法として有益な方法です。 Entity Framework データベース初期化子の詳細については、 MVC/Entity Framework のチュートリアル ASP.NET 参照してください。
  2. モデル クラスに一致するように、既存のデータベースのスキーマを明示的に変更します。 この手法の長所は、データが維持されることです。 この変更は手動で行うことも、データベース変更スクリプトを作成して行うこともできます。
  3. Code First Migrations を使用して、データベース スキーマを更新します。

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

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

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

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

add-migration Rating

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

このコマンドが完了すると、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します。

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

データベースの更新コマンドが入力された [パッケージ マネージャー コンソール] ウィンドウを示すスクリーンショット。

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

[評価] フィールドが追加された M V C Movie Index の一覧を示すスクリーンショット。

[ 新規作成 ] リンクをクリックして、新しいムービーを追加します。 評価を追加できることに注意してください。

7_CreateRioII

Create をクリックしてください。 評価を含む新しい映画が、映画の一覧に表示されるようになりました。

7_ourNewMovie_SM

プロジェクトで移行が使用されたので、新しいフィールドを追加したり、スキーマを更新したりするときにデータベースを削除する必要はありません。 次のセクションでは、スキーマをさらに変更し、移行を使用してデータベースを更新します。

また、フィールドを Rating [編集]、[詳細]、[削除] の各ビュー テンプレートに追加する必要があります。

スキーマがモデルと一致するため、 パッケージ マネージャー コンソール ウィンドウに "update-database" コマンドをもう一度入力しても、移行コードは実行されません。 ただし、"update-database" を実行するとメソッドが再度実行 Seed され、Seed データのいずれかを変更した場合、メソッドによってデータがアップサートされるため Seed 、変更は失われます。 メソッドの Seed 詳細については、Tom Dykstra の MVC /Entity Framework チュートリアル ASP.NET 人気があります。

このセクションでは、モデル オブジェクトを変更し、データベースを変更と同期する方法について説明しました。 また、シナリオを試すことができるように、新しく作成されたデータベースにサンプル データを設定する方法についても学習しました。 これは、Code First の簡単な概要でした。このテーマに関するより完全なチュートリアルについては、「 ASP.NET MVC アプリケーション用の Entity Framework データ モデルの作成 」を参照してください。 次に、モデル クラスに高度な検証ロジックを追加し、一部のビジネス ルールを適用できるようにする方法を見てみましょう。