パート 8、ASP.NET Core MVC アプリへの新しいフィールドの追加

Note

これは、この記事の最新バージョンではありません。 現在のリリースについては、この記事の .NET 8 バージョンを参照してください。

警告

このバージョンの ASP.NET Core はサポート対象から除外されました。 詳細については、「.NET および .NET Core サポート ポリシー」を参照してください。 現在のリリースについては、この記事の .NET 8 バージョンを参照してください。

重要

この情報はリリース前の製品に関する事項であり、正式版がリリースされるまでに大幅に変更される可能性があります。 Microsoft はここに示されている情報について、明示か黙示かを問わず、一切保証しません。

現在のリリースについては、この記事の .NET 8 バージョンを参照してください。

作成者: Rick Anderson

このセクションでは Entity Framework Migrations を次の目的で使用します。

  • モデルに新しいフィールドを追加する。
  • 新しいフィールドをデータベースに移行する。

Entity Framework (EF) を使用してモデル クラスからデータベースを自動的に作成する場合:

  • テーブルがデータベースに追加され、データベースのスキーマを追跡します。
  • データベースが、生成されたモデル クラスと同期されていることが確認されます。 同期していない場合、EF は例外をスローします。 一貫性のないデータベース/コードの問題を簡単に見つけられます。

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

Rating プロパティを Models/Movie.cs に追加します。

using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;

namespace MvcMovie.Models;

public class Movie
{
    public int Id { get; set; }
    public string? Title { get; set; }

    [Display(Name = "Release Date")]
    [DataType(DataType.Date)]
    public DateTime ReleaseDate { get; set; }
    public string? Genre { get; set; }
    
    [Column(TypeName = "decimal(18, 2)")]
    public decimal Price { get; set; }
    public string? Rating {  get; set; }
}

アプリをビルドする

Ctrl+Shift+B キーを押します

新しいフィールドを Movie クラスに追加したので、この新しいプロパティが含まれるようにプロパティ バインディング リストを更新する必要があります。 MoviesController.cs で、CreateEdit の両方のアクション メソッドの [Bind] 属性を更新して、Rating プロパティが含まれるようにします。

[Bind("Id,Title,ReleaseDate,Genre,Price,Rating")]

ブラウザー ビューで新しい Rating プロパティを表示、作成、編集するためにビュー テンプレートを更新します。

/Views/Movies/Index.cshtml ファイルを編集し、Rating フィールドを追加します。

<table class="table">
    <thead>
        <tr>
            <th>
                @Html.DisplayNameFor(model => model.Movies![0].Title)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.Movies![0].ReleaseDate)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.Movies![0].Genre)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.Movies![0].Price)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.Movies![0].Rating)
            </th>
            <th></th>
        </tr>
    </thead>
    <tbody>
        @foreach (var item in Model.Movies!)
        {
            <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>
                    <a asp-action="Edit" asp-route-id="@item.Id">Edit</a> |
                    <a asp-action="Details" asp-route-id="@item.Id">Details</a> |
                    <a asp-action="Delete" asp-route-id="@item.Id">Delete</a>
                </td>
            </tr>
        }
    </tbody>
</table>

/Views/Movies/Create.cshtmlRating フィールドで更新します。

前の "form group" をコピー/貼り付けし、intelliSense にフィールドを更新させることができます。 IntelliSense はタグ ヘルパーと連動します。

開発者は、ビューの 2 番目のラベル要素で、asp-for の属性値に文字 R を入力しました。Intellisense のコンテキスト メニューが表示され、[評価] を含む、利用可能なフィールドが表示されました。[評価] は一覧の中で自動的に強調表示されています。開発者はこのフィールドをクリックするか、キーボードの Enter を押すと、値が [評価] に設定されます。

Rating プロパティを、残りの Create.cshtmlDelete.cshtmlDetails.cshtmlEdit.cshtml ビュー テンプレートに追加します。

新しい列に値を提供するように、SeedData クラスを更新します。 下に変更のサンプルがありますが、new Movie ごとにこの変更を行ってください。

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

DB を更新して新しいフィールドが含まれるようになるまでアプリは動作しません。 ここで実行すると、次の SqlException がスローされます。

SqlException: Invalid column name 'Rating'.

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

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

  1. Entity Framework に、新しいモデル クラス スキーマに基づいてデータベースを自動的にドロップさせ、再作成させます。 この手法は、開発周期の早い段階で、テスト データベースで開発しているときに非常に便利です。モデルとデータベース スキーマを一緒に短期間で発展させることができます。 ただし、欠点もあり、データベースの既存データが失われます。本稼働データベースではこの手法は推奨されません。 初期化子を利用し、データベースにテスト データを自動的に初期投入します。多くの場合、アプリケーション開発の手法として有益な方法です。 これは、初期の開発や SQLite を使用するときに適した方法です。

  2. モデル クラスに一致するように、既存のデータベースのスキーマを明示的に変更します。 この手法の長所は、データが維持されることです。 この変更は手動で行うことも、データベース変更スクリプトを作成して行うこともできます。

  3. Entity Framework Migrations を使用してデータベース スキーマを更新します。

このチュートリアルでは、Entity Framework Migrations を使用します。

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

PMC メニュー

パッケージ マネージャー コンソールで、次のコマンドを入力します。

Add-Migration Rating

Add-Migration コマンドは移行フレームワークに現在の Movie モデルを現在の Movie DB スキーマで調べ、DB を新しいモデルに移行するために必要なコードを作成します。

"Rating (評価)" という名前は任意です。移行ファイルに名前を付けるために利用されます。 移行ファイルには意味のある名前を使用すると便利です。

DB 内のレコードをすべて削除すると、初期化メソッドで DB がシードされ、Rating フィールドが追加されします。

パッケージ マネージャー コンソールで、次のコマンドを入力します。

Update-Database

Update-Database コマンドにより、適用されていない移行で Up メソッドが実行されます。

アプリを実行し、Rating フィールドでムービーを作成、編集、表示できることを確認します。

このセクションでは Entity Framework Code First Migrations を次の目的で使用します。

  • モデルに新しいフィールドを追加する。
  • 新しいフィールドをデータベースに移行する。

EF Code First を使用してデータベースを自動的に作成する場合、Code First では次が実行されます。

  • テーブルをデータベースに追加して、データベースのスキーマを追跡します。
  • データベースが生成されたモデル クラスと同期されていることを確認します。 同期していない場合、EF は例外をスローします。 一貫性のないデータベース/コードの問題を簡単に見つけられます。

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

Rating プロパティを Models/Movie.cs に追加します。

using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;

namespace MvcMovie.Models;

public class Movie
{
    public int Id { get; set; }
    public string? Title { get; set; }

    [Display(Name = "Release Date")]
    [DataType(DataType.Date)]
    public DateTime ReleaseDate { get; set; }
    public string? Genre { get; set; }
    
    [Column(TypeName = "decimal(18, 2)")]
    public decimal Price { get; set; }
    public string? Rating {  get; set; }
}

アプリをビルドする

Ctrl+Shift+B キーを押します

新しいフィールドを Movie クラスに追加したので、この新しいプロパティが含まれるようにプロパティ バインディング リストを更新する必要があります。 MoviesController.cs で、CreateEdit の両方のアクション メソッドの [Bind] 属性を更新して、Rating プロパティが含まれるようにします。

[Bind("Id,Title,ReleaseDate,Genre,Price,Rating")]

ブラウザー ビューで新しい Rating プロパティを表示、作成、編集するためにビュー テンプレートを更新します。

/Views/Movies/Index.cshtml ファイルを編集し、Rating フィールドを追加します。

<table class="table">
    <thead>
        <tr>
            <th>
                @Html.DisplayNameFor(model => model.Movies![0].Title)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.Movies![0].ReleaseDate)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.Movies![0].Genre)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.Movies![0].Price)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.Movies![0].Rating)
            </th>
            <th></th>
        </tr>
    </thead>
    <tbody>
        @foreach (var item in Model.Movies!)
        {
            <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>
                    <a asp-action="Edit" asp-route-id="@item.Id">Edit</a> |
                    <a asp-action="Details" asp-route-id="@item.Id">Details</a> |
                    <a asp-action="Delete" asp-route-id="@item.Id">Delete</a>
                </td>
            </tr>
        }
    </tbody>
</table>

/Views/Movies/Create.cshtmlRating フィールドで更新します。

前の "form group" をコピー/貼り付けし、intelliSense にフィールドを更新させることができます。 IntelliSense はタグ ヘルパーと連動します。

開発者は、ビューの 2 番目のラベル要素で、asp-for の属性値に文字 R を入力しました。Intellisense のコンテキスト メニューが表示され、[評価] を含む、利用可能なフィールドが表示されました。[評価] は一覧の中で自動的に強調表示されています。開発者はこのフィールドをクリックするか、キーボードの Enter を押すと、値が [評価] に設定されます。

残りのテンプレートを更新します。

新しい列に値を提供するように、SeedData クラスを更新します。 下に変更のサンプルがありますが、new Movie ごとにこの変更を行ってください。

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

DB を更新して新しいフィールドが含まれるようになるまでアプリは動作しません。 ここで実行すると、次の SqlException がスローされます。

SqlException: Invalid column name 'Rating'.

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

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

  1. Entity Framework に、新しいモデル クラス スキーマに基づいてデータベースを自動的にドロップさせ、再作成させます。 この手法は、開発周期の早い段階で、テスト データベースで開発しているときに非常に便利です。モデルとデータベース スキーマを一緒に短期間で発展させることができます。 ただし、欠点もあり、データベースの既存データが失われます。本稼働データベースではこの手法は推奨されません。 初期化子を利用し、データベースにテスト データを自動的に初期投入します。多くの場合、アプリケーション開発の手法として有益な方法です。 これは、初期の開発や SQLite を使用するときに適した方法です。

  2. モデル クラスに一致するように、既存のデータベースのスキーマを明示的に変更します。 この手法の長所は、データが維持されることです。 この変更は手動で行うことも、データベース変更スクリプトを作成して行うこともできます。

  3. Code First Migrations を使用して、データベース スキーマを更新します。

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

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

PMC メニュー

PMC で、次のコマンドを入力します。

Add-Migration Rating
Update-Database

Add-Migration コマンドは移行フレームワークに現在の Movie モデルを現在の Movie DB スキーマで調べ、DB を新しいモデルに移行するために必要なコードを作成します。

"Rating (評価)" という名前は任意です。移行ファイルに名前を付けるために利用されます。 移行ファイルには意味のある名前を使用すると便利です。

DB 内のレコードをすべて削除すると、初期化メソッドで DB がシードされ、Rating フィールドが追加されします。

アプリを実行し、Rating フィールドでムービーを作成、編集、表示できることを確認します。

このセクションでは Entity Framework Code First Migrations を次の目的で使用します。

  • モデルに新しいフィールドを追加する。
  • 新しいフィールドをデータベースに移行する。

EF Code First を使用してデータベースを自動的に作成する場合、Code First では次が実行されます。

  • テーブルをデータベースに追加して、データベースのスキーマを追跡します。
  • データベースが生成されたモデル クラスと同期されていることを確認します。 同期していない場合、EF は例外をスローします。 一貫性のないデータベース/コードの問題を簡単に見つけられます。

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

Rating プロパティを Models/Movie.cs に追加します。

using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;

namespace MvcMovie.Models;

public class Movie
{
    public int Id { get; set; }
    public string? Title { get; set; }

    [Display(Name = "Release Date")]
    [DataType(DataType.Date)]
    public DateTime ReleaseDate { get; set; }
    public string? Genre { get; set; }
    
    [Column(TypeName = "decimal(18, 2)")]
    public decimal Price { get; set; }
    public string? Rating {  get; set; }
}

アプリをビルドする

Ctrl+Shift+B キーを押します

新しいフィールドを Movie クラスに追加したので、この新しいプロパティが含まれるようにプロパティ バインディング リストを更新する必要があります。 MoviesController.cs で、CreateEdit の両方のアクション メソッドの [Bind] 属性を更新して、Rating プロパティが含まれるようにします。

[Bind("Id,Title,ReleaseDate,Genre,Price,Rating")]

ブラウザー ビューで新しい Rating プロパティを表示、作成、編集するためにビュー テンプレートを更新します。

/Views/Movies/Index.cshtml ファイルを編集し、Rating フィールドを追加します。

<table class="table">
    <thead>
        <tr>
            <th>
                @Html.DisplayNameFor(model => model.Movies![0].Title)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.Movies![0].ReleaseDate)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.Movies![0].Genre)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.Movies![0].Price)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.Movies![0].Rating)
            </th>
            <th></th>
        </tr>
    </thead>
    <tbody>
        @foreach (var item in Model.Movies!)
        {
            <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>
                    <a asp-action="Edit" asp-route-id="@item.Id">Edit</a> |
                    <a asp-action="Details" asp-route-id="@item.Id">Details</a> |
                    <a asp-action="Delete" asp-route-id="@item.Id">Delete</a>
                </td>
            </tr>
        }
    </tbody>
</table>

/Views/Movies/Create.cshtmlRating フィールドで更新します。

前の "form group" をコピー/貼り付けし、intelliSense にフィールドを更新させることができます。 IntelliSense はタグ ヘルパーと連動します。

開発者は、ビューの 2 番目のラベル要素で、asp-for の属性値に文字 R を入力しました。Intellisense のコンテキスト メニューが表示され、[評価] を含む、利用可能なフィールドが表示されました。[評価] は一覧の中で自動的に強調表示されています。開発者はこのフィールドをクリックするか、キーボードの Enter を押すと、値が [評価] に設定されます。

残りのテンプレートを更新します。

新しい列に値を提供するように、SeedData クラスを更新します。 下に変更のサンプルがありますが、new Movie ごとにこの変更を行ってください。

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

DB を更新して新しいフィールドが含まれるようになるまでアプリは動作しません。 ここで実行すると、次の SqlException がスローされます。

SqlException: Invalid column name 'Rating'.

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

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

  1. Entity Framework に、新しいモデル クラス スキーマに基づいてデータベースを自動的にドロップさせ、再作成させます。 この手法は、開発周期の早い段階で、テスト データベースで開発しているときに非常に便利です。モデルとデータベース スキーマを一緒に短期間で発展させることができます。 ただし、欠点もあり、データベースの既存データが失われます。本稼働データベースではこの手法は推奨されません。 初期化子を利用し、データベースにテスト データを自動的に初期投入します。多くの場合、アプリケーション開発の手法として有益な方法です。 これは、初期の開発や SQLite を使用するときに適した方法です。

  2. モデル クラスに一致するように、既存のデータベースのスキーマを明示的に変更します。 この手法の長所は、データが維持されることです。 この変更は手動で行うことも、データベース変更スクリプトを作成して行うこともできます。

  3. Code First Migrations を使用して、データベース スキーマを更新します。

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

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

PMC メニュー

PMC で、次のコマンドを入力します。

Add-Migration Rating
Update-Database

Add-Migration コマンドは移行フレームワークに現在の Movie モデルを現在の Movie DB スキーマで調べ、DB を新しいモデルに移行するために必要なコードを作成します。

"Rating (評価)" という名前は任意です。移行ファイルに名前を付けるために利用されます。 移行ファイルには意味のある名前を使用すると便利です。

DB 内のレコードをすべて削除すると、初期化メソッドで DB がシードされ、Rating フィールドが追加されします。

アプリを実行し、Rating フィールドでムービーを作成、編集、表示できることを確認します。

このセクションでは Entity Framework Code First Migrations を次の目的で使用します。

  • モデルに新しいフィールドを追加する。
  • 新しいフィールドをデータベースに移行する。

EF Code First を使用してデータベースを自動的に作成する場合、Code First では次が実行されます。

  • テーブルをデータベースに追加して、データベースのスキーマを追跡します。
  • データベースが生成されたモデル クラスと同期されていることを確認します。 同期していない場合、EF は例外をスローします。 一貫性のないデータベース/コードの問題を簡単に見つけられます。

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

Rating プロパティを Models/Movie.cs に追加します。

using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;

namespace MvcMovie.Models
{
    public class Movie
    {
        public int Id { get; set; }
        public string? Title { get; set; }

        [Display(Name = "Release Date")]
        [DataType(DataType.Date)]
        public DateTime ReleaseDate { get; set; }
        public string? Genre { get; set; }

        [Column(TypeName = "decimal(18, 2)")]
        public decimal Price { get; set; }
        public string? Rating {  get; set; }
    }
}

アプリをビルドする

Ctrl + Shift + B

新しいフィールドを Movie クラスに追加したので、この新しいプロパティが含まれるようにプロパティ バインディング リストを更新する必要があります。 MoviesController.cs で、CreateEdit の両方のアクション メソッドの [Bind] 属性を更新して、Rating プロパティが含まれるようにします。

[Bind("Id,Title,ReleaseDate,Genre,Price,Rating")]

ブラウザー ビューで新しい Rating プロパティを表示、作成、編集するためにビュー テンプレートを更新します。

/Views/Movies/Index.cshtml ファイルを編集し、Rating フィールドを追加します。

<table class="table">
    <thead>
        <tr>
            <th>
                @Html.DisplayNameFor(model => model.Movies[0].Title)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.Movies[0].ReleaseDate)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.Movies[0].Genre)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.Movies[0].Price)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.Movies[0].Rating)
            </th>
            <th></th>
        </tr>
    </thead>
    <tbody>
        @foreach (var item in Model.Movies)
        {
            <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>
                    <a asp-action="Edit" asp-route-id="@item.Id">Edit</a> |
                    <a asp-action="Details" asp-route-id="@item.Id">Details</a> |
                    <a asp-action="Delete" asp-route-id="@item.Id">Delete</a>
                </td>
            </tr>
        }
    </tbody>
</table>

/Views/Movies/Create.cshtmlRating フィールドで更新します。

前の "form group" をコピー/貼り付けし、intelliSense にフィールドを更新させることができます。 IntelliSense はタグ ヘルパーと連動します。

開発者は、ビューの 2 番目のラベル要素で、asp-for の属性値に文字 R を入力しました。Intellisense のコンテキスト メニューが表示され、[評価] を含む、利用可能なフィールドが表示されました。[評価] は一覧の中で自動的に強調表示されています。開発者はこのフィールドをクリックするか、キーボードの Enter を押すと、値が [評価] に設定されます。

残りのテンプレートを更新します。

新しい列に値を提供するように、SeedData クラスを更新します。 下に変更のサンプルがありますが、new Movie ごとにこの変更を行ってください。

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

DB を更新して新しいフィールドが含まれるようになるまでアプリは動作しません。 ここで実行すると、次の SqlException がスローされます。

SqlException: Invalid column name 'Rating'.

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

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

  1. Entity Framework に、新しいモデル クラス スキーマに基づいてデータベースを自動的にドロップさせ、再作成させます。 この手法は、開発周期の早い段階で、テスト データベースで開発しているときに非常に便利です。モデルとデータベース スキーマを一緒に短期間で発展させることができます。 ただし、欠点もあり、データベースの既存データが失われます。本稼働データベースではこの手法は推奨されません。 初期化子を利用し、データベースにテスト データを自動的に初期投入します。多くの場合、アプリケーション開発の手法として有益な方法です。 これは、初期の開発や SQLite を使用するときに適した方法です。

  2. モデル クラスに一致するように、既存のデータベースのスキーマを明示的に変更します。 この手法の長所は、データが維持されることです。 この変更は手動で行うことも、データベース変更スクリプトを作成して行うこともできます。

  3. Code First Migrations を使用して、データベース スキーマを更新します。

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

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

PMC メニュー

PMC で、次のコマンドを入力します。

Add-Migration Rating
Update-Database

Add-Migration コマンドは移行フレームワークに現在の Movie モデルを現在の Movie DB スキーマで調べ、DB を新しいモデルに移行するために必要なコードを作成します。

"Rating (評価)" という名前は任意です。移行ファイルに名前を付けるために利用されます。 移行ファイルには意味のある名前を使用すると便利です。

DB 内のレコードをすべて削除すると、初期化メソッドで DB がシードされ、Rating フィールドが追加されします。

アプリを実行し、Rating フィールドでムービーを作成、編集、表示できることを確認します。

このセクションでは Entity Framework Code First Migrations を次の目的で使用します。

  • モデルに新しいフィールドを追加する。
  • 新しいフィールドをデータベースに移行する。

EF Code First を使用してデータベースを自動的に作成する場合、Code First では次が実行されます。

  • テーブルをデータベースに追加して、データベースのスキーマを追跡します。
  • データベースが生成されたモデル クラスと同期されていることを確認します。 同期していない場合、EF は例外をスローします。 一貫性のないデータベース/コードの問題を簡単に見つけられます。

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

Rating プロパティを Models/Movie.cs に追加します。

using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;

namespace MvcMovie.Models
{
    public class Movie
    {
        public int Id { get; set; }
        public string Title { get; set; }

        [Display(Name = "Release Date")]
        [DataType(DataType.Date)]
        public DateTime ReleaseDate { get; set; }
        public string Genre { get; set; }

        [Column(TypeName = "decimal(18, 2)")]
        public decimal Price { get; set; }
        public string Rating { get; set; }
    }
}

アプリをビルドする

Ctrl + Shift + B

新しいフィールドを Movie クラスに追加したので、この新しいプロパティが含まれるようにプロパティ バインディング リストを更新する必要があります。 MoviesController.cs で、CreateEdit の両方のアクション メソッドの [Bind] 属性を更新して、Rating プロパティが含まれるようにします。

[Bind("Id,Title,ReleaseDate,Genre,Price,Rating")]

ブラウザー ビューで新しい Rating プロパティを表示、作成、編集するためにビュー テンプレートを更新します。

/Views/Movies/Index.cshtml ファイルを編集し、Rating フィールドを追加します。

<thead>
    <tr>
        <th>
            @Html.DisplayNameFor(model => model.Movies[0].Title)
        </th>
        <th>
            @Html.DisplayNameFor(model => model.Movies[0].ReleaseDate)
        </th>
        <th>
            @Html.DisplayNameFor(model => model.Movies[0].Genre)
        </th>
        <th>
            @Html.DisplayNameFor(model => model.Movies[0].Price)
        </th>
        <th>
            @Html.DisplayNameFor(model => model.Movies[0].Rating)
        </th>
        <th></th>
    </tr>
</thead>
<tbody>
    @foreach (var item in Model.Movies)
    {
        <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>

/Views/Movies/Create.cshtmlRating フィールドで更新します。

前の "form group" をコピー/貼り付けし、intelliSense にフィールドを更新させることができます。 IntelliSense はタグ ヘルパーと連動します。

開発者は、ビューの 2 番目のラベル要素で、asp-for の属性値に文字 R を入力しました。Intellisense のコンテキスト メニューが表示され、[評価] を含む、利用可能なフィールドが表示されました。[評価] は一覧の中で自動的に強調表示されています。開発者はこのフィールドをクリックするか、キーボードの Enter を押すと、値が [評価] に設定されます。

残りのテンプレートを更新します。

新しい列に値を提供するように、SeedData クラスを更新します。 下に変更のサンプルがありますが、new Movie ごとにこの変更を行ってください。

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

DB を更新して新しいフィールドが含まれるようになるまでアプリは動作しません。 ここで実行すると、次の SqlException がスローされます。

SqlException: Invalid column name 'Rating'.

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

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

  1. Entity Framework に、新しいモデル クラス スキーマに基づいてデータベースを自動的にドロップさせ、再作成させます。 この手法は、開発周期の早い段階で、テスト データベースで開発しているときに非常に便利です。モデルとデータベース スキーマを一緒に短期間で発展させることができます。 ただし、欠点もあり、データベースの既存データが失われます。本稼働データベースではこの手法は推奨されません。 初期化子を利用し、データベースにテスト データを自動的に初期投入します。多くの場合、アプリケーション開発の手法として有益な方法です。 これは、初期の開発や SQLite を使用するときに適した方法です。

  2. モデル クラスに一致するように、既存のデータベースのスキーマを明示的に変更します。 この手法の長所は、データが維持されることです。 この変更は手動で行うことも、データベース変更スクリプトを作成して行うこともできます。

  3. Code First Migrations を使用して、データベース スキーマを更新します。

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

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

PMC メニュー

PMC で、次のコマンドを入力します。

Add-Migration Rating
Update-Database

Add-Migration コマンドは移行フレームワークに現在の Movie モデルを現在の Movie DB スキーマで調べ、DB を新しいモデルに移行するために必要なコードを作成します。

"Rating (評価)" という名前は任意です。移行ファイルに名前を付けるために利用されます。 移行ファイルには意味のある名前を使用すると便利です。

DB 内のレコードをすべて削除すると、初期化メソッドで DB がシードされ、Rating フィールドが追加されします。

アプリを実行し、Rating フィールドでムービーを作成、編集、表示できることを確認します。

このセクションでは Entity Framework Code First Migrations を次の目的で使用します。

  • モデルに新しいフィールドを追加する。
  • 新しいフィールドをデータベースに移行する。

EF Code First を使用してデータベースを自動的に作成する場合、Code First では次が実行されます。

  • テーブルをデータベースに追加して、データベースのスキーマを追跡します。
  • データベースが生成されたモデル クラスと同期されていることを確認します。 同期していない場合、EF は例外をスローします。 一貫性のないデータベース/コードの問題を簡単に見つけられます。

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

Rating プロパティを Models/Movie.cs に追加します。

using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;

namespace MvcMovie.Models
{
    public class Movie
    {
        public int Id { get; set; }
        public string Title { get; set; }

        [Display(Name = "Release Date")]
        [DataType(DataType.Date)]
        public DateTime ReleaseDate { get; set; }
        public string Genre { get; set; }

        [Column(TypeName = "decimal(18, 2)")]
        public decimal Price { get; set; }
        public string Rating { get; set; }
    }
}

アプリをビルドする

Ctrl + Shift + B

新しいフィールドを Movie クラスに追加したので、この新しいプロパティが含まれるようにプロパティ バインディング リストを更新する必要があります。 MoviesController.cs で、CreateEdit の両方のアクション メソッドの [Bind] 属性を更新して、Rating プロパティが含まれるようにします。

[Bind("Id,Title,ReleaseDate,Genre,Price,Rating")]

ブラウザー ビューで新しい Rating プロパティを表示、作成、編集するためにビュー テンプレートを更新します。

/Views/Movies/Index.cshtml ファイルを編集し、Rating フィールドを追加します。

<thead>
    <tr>
        <th>
            @Html.DisplayNameFor(model => model.Movies[0].Title)
        </th>
        <th>
            @Html.DisplayNameFor(model => model.Movies[0].ReleaseDate)
        </th>
        <th>
            @Html.DisplayNameFor(model => model.Movies[0].Genre)
        </th>
        <th>
            @Html.DisplayNameFor(model => model.Movies[0].Price)
        </th>
        <th>
            @Html.DisplayNameFor(model => model.Movies[0].Rating)
        </th>
        <th></th>
    </tr>
</thead>
<tbody>
    @foreach (var item in Model.Movies)
    {
        <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>

/Views/Movies/Create.cshtmlRating フィールドで更新します。

前の "form group" をコピー/貼り付けし、intelliSense にフィールドを更新させることができます。 IntelliSense はタグ ヘルパーと連動します。

開発者は、ビューの 2 番目のラベル要素で、asp-for の属性値に文字 R を入力しました。Intellisense のコンテキスト メニューが表示され、[評価] を含む、利用可能なフィールドが表示されました。[評価] は一覧の中で自動的に強調表示されています。開発者はこのフィールドをクリックするか、キーボードの Enter を押すと、値が [評価] に設定されます。

残りのテンプレートを更新します。

新しい列に値を提供するように、SeedData クラスを更新します。 下に変更のサンプルがありますが、new Movie ごとにこの変更を行ってください。

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

DB を更新して新しいフィールドが含まれるようになるまでアプリは動作しません。 ここで実行すると、次の SqlException がスローされます。

SqlException: Invalid column name 'Rating'.

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

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

  1. Entity Framework に、新しいモデル クラス スキーマに基づいてデータベースを自動的にドロップさせ、再作成させます。 この手法は、開発周期の早い段階で、テスト データベースで開発しているときに非常に便利です。モデルとデータベース スキーマを一緒に短期間で発展させることができます。 ただし、欠点もあり、データベースの既存データが失われます。本稼働データベースではこの手法は推奨されません。 初期化子を利用し、データベースにテスト データを自動的に初期投入します。多くの場合、アプリケーション開発の手法として有益な方法です。 これは、初期の開発や SQLite を使用するときに適した方法です。

  2. モデル クラスに一致するように、既存のデータベースのスキーマを明示的に変更します。 この手法の長所は、データが維持されることです。 この変更は手動で行うことも、データベース変更スクリプトを作成して行うこともできます。

  3. Code First Migrations を使用して、データベース スキーマを更新します。

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

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

PMC メニュー

PMC で、次のコマンドを入力します。

Add-Migration Rating
Update-Database

Add-Migration コマンドは移行フレームワークに現在の Movie モデルを現在の Movie DB スキーマで調べ、DB を新しいモデルに移行するために必要なコードを作成します。

"Rating (評価)" という名前は任意です。移行ファイルに名前を付けるために利用されます。 移行ファイルには意味のある名前を使用すると便利です。

DB 内のレコードをすべて削除すると、初期化メソッドで DB がシードされ、Rating フィールドが追加されします。

アプリを実行し、Rating フィールドでムービーを作成、編集、表示できることを確認します。