パート 7、ASP.NET Core で Razor ページでの新しいフィールドの追加

Note

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

重要

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

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

作成者: Rick Anderson

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

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

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

  • データベースに __EFMigrationsHistory テーブルが追加され、データベースのスキーマが生成元のモデル クラスと同期しているかどうかが追跡されます。
  • モデル クラスがデータベースと同期されていない場合、例外がスローされます。

スキーマとモデルが同期中であることが自動的に検証されるようにすると、整合性のないデータベース コードの問題を発見しやすくなります。

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

  1. Models/Movie.cs ファイルを開き、Rating プロパティを追加します。

    public class Movie
    {
        public int Id { get; set; }
        public string Title { get; set; } = string.Empty;
    
        [Display(Name = "Release Date")]
        [DataType(DataType.Date)]
        public DateTime ReleaseDate { get; set; }
        public string Genre { get; set; } = string.Empty;
    
        [Column(TypeName = "decimal(18, 2)")]
        public decimal Price { get; set; }
        public string Rating { get; set; } = string.Empty;
    }
    
  2. Pages/Movies/Index.cshtml を編集し、Rating フィールドを追加します ()。

    @page
    @model RazorPagesMovie.Pages.Movies.IndexModel
    
    @{
        ViewData["Title"] = "Index";
    }
    
    <h1>Index</h1>
    
    <p>
        <a asp-page="Create">Create New</a>
    </p>
    
    <form>
        <p>
            <select asp-for="MovieGenre" asp-items="Model.Genres">
                <option value="">All</option>
            </select>
            Title: <input type="text" asp-for="SearchString" />
            <input type="submit" value="Filter" />
        </p>
    </form>
    
    <table class="table">
    
        <thead>
            <tr>
                <th>
                    @Html.DisplayNameFor(model => model.Movie[0].Title)
                </th>
                <th>
                    @Html.DisplayNameFor(model => model.Movie[0].ReleaseDate)
                </th>
                <th>
                    @Html.DisplayNameFor(model => model.Movie[0].Genre)
                </th>
                <th>
                    @Html.DisplayNameFor(model => model.Movie[0].Price)
                </th>
                <th>
                    @Html.DisplayNameFor(model => model.Movie[0].Rating)
                </th>
                <th></th>
            </tr>
        </thead>
        <tbody>
            @foreach (var item in Model.Movie)
            {
                <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-page="./Edit" asp-route-id="@item.Id">Edit</a> |
                        <a asp-page="./Details" asp-route-id="@item.Id">Details</a> |
                        <a asp-page="./Delete" asp-route-id="@item.Id">Delete</a>
                    </td>
                </tr>
            }
        </tbody>
    </table>
    
  3. 次のページを Rating フィールドで更新します。

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

SqlException: Invalid column name 'Rating'.

SqlException 例外が発生するのは、更新された Movie モデル クラスが、データベースの Movie テーブルのスキーマと異なるためです。 データベース テーブルに Rating 列はありません。

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

  1. Entity Framework に、新しいモデル クラス スキーマを使用してデータベースを自動的にドロップさせ、再作成させます。 この手法は、開発周期の早い段階で便利です。開発者はモデルとデータベース スキーマを一緒に短期間で発展させることができます。 これの欠点は、データベース内の既存のデータが失われることです。 実稼働データベースでこの方法は使用しないでください。 スキーマの変更時にデータベースを削除し、初期化子を使用して、データベースにテスト データを自動的にシードすることは、多くの場合、アプリケーションを開発する上で有益な方法となります。
  2. モデル クラスに一致するように、既存のデータベースのスキーマを明示的に変更します。 この手法の長所は、データが維持されることです。 この変更は手動で行うか、データベース変更スクリプトを作成して行います。
  3. Code First Migrations を使用して、データベース スキーマを更新します。

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

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

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

完成した SeedData.cs ファイルを参照してください。

アプリをビルドする

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

評価フィールドの移行を追加する

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

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

    Add-Migration Rating
    Update-Database
    

Add-Migration コマンドにより、フレームワークに次の指示があります。

  • Movie モデルを、Movie データベースのスキーマと比較します。
  • データベース スキーマを新しいモデルに移行するコードを作成します。

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

Update-Database コマンドを使うと、データベースにスキーマ変更を適用し、既存のデータを保持するようにフレームワークに指示できます。

データベース内のすべてのレコードを削除すると、初期化子はデータベースにデータを初期投入し、Rating フィールドを追加します。 削除は、ブラウザーの削除リンクを使用するか、Sql Server Object Explorer (SSOX) から実行できます。

別のオプションとしては、データベースを削除してから、移行を使用することで、データベースを再作成することもできます。 SSOX 内でデータベースを削除するには:

  1. SSOX でデータベースを選択します。

  2. データベースを右クリックし、 [削除] を選択します。

  3. [既存の接続を閉じる] をチェックします。

  4. [OK] を選択します。

  5. PMC でデータベースを更新します。

    Update-Database
    

アプリを実行し、Rating フィールドでムービーを作成、編集、表示できることを確認します。 データベースがシード処理されない場合は、SeedData.Initialize メソッドでブレークポイントを設定します。

次のステップ

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

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

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

  • データベースに __EFMigrationsHistory テーブルが追加され、データベースのスキーマが生成元のモデル クラスと同期しているかどうかが追跡されます。
  • モデル クラスがデータベースと同期されていない場合、例外がスローされます。

スキーマとモデルが同期中であることが自動的に検証されるようにすると、整合性のないデータベース コードの問題を発見しやすくなります。

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

  1. Models/Movie.cs ファイルを開き、Rating プロパティを追加します。

    public class Movie
    {
        public int Id { get; set; }
        public string Title { get; set; } = string.Empty;
    
        [Display(Name = "Release Date")]
        [DataType(DataType.Date)]
        public DateTime ReleaseDate { get; set; }
        public string Genre { get; set; } = string.Empty;
    
        [Column(TypeName = "decimal(18, 2)")]
        public decimal Price { get; set; }
        public string Rating { get; set; } = string.Empty;
    }
    
  2. Pages/Movies/Index.cshtml を編集し、Rating フィールドを追加します ()。

    @page
    @model RazorPagesMovie.Pages.Movies.IndexModel
    
    @{
        ViewData["Title"] = "Index";
    }
    
    <h1>Index</h1>
    
    <p>
        <a asp-page="Create">Create New</a>
    </p>
    
    <form>
        <p>
            <select asp-for="MovieGenre" asp-items="Model.Genres">
                <option value="">All</option>
            </select>
            Title: <input type="text" asp-for="SearchString" />
            <input type="submit" value="Filter" />
        </p>
    </form>
    
    <table class="table">
    
        <thead>
            <tr>
                <th>
                    @Html.DisplayNameFor(model => model.Movie[0].Title)
                </th>
                <th>
                    @Html.DisplayNameFor(model => model.Movie[0].ReleaseDate)
                </th>
                <th>
                    @Html.DisplayNameFor(model => model.Movie[0].Genre)
                </th>
                <th>
                    @Html.DisplayNameFor(model => model.Movie[0].Price)
                </th>
                <th>
                    @Html.DisplayNameFor(model => model.Movie[0].Rating)
                </th>
                <th></th>
            </tr>
        </thead>
        <tbody>
            @foreach (var item in Model.Movie)
            {
                <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-page="./Edit" asp-route-id="@item.Id">Edit</a> |
                        <a asp-page="./Details" asp-route-id="@item.Id">Details</a> |
                        <a asp-page="./Delete" asp-route-id="@item.Id">Delete</a>
                    </td>
                </tr>
            }
        </tbody>
    </table>
    
  3. 次のページを Rating フィールドで更新します。

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

SqlException: Invalid column name 'Rating'.

SqlException 例外が発生するのは、更新された Movie モデル クラスが、データベースの Movie テーブルのスキーマと異なるためです。 データベース テーブルに Rating 列はありません。

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

  1. Entity Framework に、新しいモデル クラス スキーマを使用してデータベースを自動的にドロップさせ、再作成させます。 この手法は、開発周期の早い段階で便利です。開発者はモデルとデータベース スキーマを一緒に短期間で発展させることができます。 これの欠点は、データベース内の既存のデータが失われることです。 実稼働データベースでこの方法は使用しないでください。 スキーマの変更時にデータベースを削除し、初期化子を使用して、データベースにテスト データを自動的にシードすることは、多くの場合、アプリケーションを開発する上で有益な方法となります。
  2. モデル クラスに一致するように、既存のデータベースのスキーマを明示的に変更します。 この手法の長所は、データが維持されることです。 この変更は手動で行うか、データベース変更スクリプトを作成して行います。
  3. Code First Migrations を使用して、データベース スキーマを更新します。

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

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

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

完成した SeedData.cs ファイルを参照してください。

アプリをビルドする

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

評価フィールドの移行を追加する

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

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

    Add-Migration Rating
    Update-Database
    

Add-Migration コマンドにより、フレームワークに次の指示があります。

  • Movie モデルを、Movie データベースのスキーマと比較します。
  • データベース スキーマを新しいモデルに移行するコードを作成します。

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

Update-Database コマンドを使うと、データベースにスキーマ変更を適用し、既存のデータを保持するようにフレームワークに指示できます。

データベース内のすべてのレコードを削除すると、初期化子はデータベースにデータを初期投入し、Rating フィールドを追加します。 削除は、ブラウザーの削除リンクを使用するか、Sql Server Object Explorer (SSOX) から実行できます。

別のオプションとしては、データベースを削除してから、移行を使用することで、データベースを再作成することもできます。 SSOX 内でデータベースを削除するには:

  1. SSOX でデータベースを選択します。

  2. データベースを右クリックし、 [削除] を選択します。

  3. [既存の接続を閉じる] をチェックします。

  4. [OK] を選択します。

  5. PMC でデータベースを更新します。

    Update-Database
    

アプリを実行し、Rating フィールドでムービーを作成、編集、表示できることを確認します。 データベースがシード処理されない場合は、SeedData.Initialize メソッドでブレークポイントを設定します。

次のステップ

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

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

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

  • データベースに __EFMigrationsHistory テーブルが追加され、データベースのスキーマが生成元のモデル クラスと同期しているかどうかが追跡されます。
  • モデル クラスがデータベースと同期されていない場合、例外がスローされます。

スキーマとモデルが同期中であることが自動的に検証されるようにすると、整合性のないデータベース コードの問題を発見しやすくなります。

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

  1. Models/Movie.cs ファイルを開き、Rating プロパティを追加します。

    public class Movie
    {
        public int ID { get; set; }
        public string Title { get; set; } = string.Empty;
    
        [Display(Name = "Release Date")]
        [DataType(DataType.Date)]
        public DateTime ReleaseDate { get; set; }
        public string Genre { get; set; } = string.Empty;
    
        [Column(TypeName = "decimal(18, 2)")]
        public decimal Price { get; set; }
        public string Rating { get; set; } = string.Empty;
    }
    
  2. Pages/Movies/Index.cshtml を編集し、Rating フィールドを追加します ()。

    @page
    @model RazorPagesMovie.Pages.Movies.IndexModel
    
    @{
        ViewData["Title"] = "Index";
    }
    
    <h1>Index</h1>
    
    <p>
        <a asp-page="Create">Create New</a>
    </p>
    
    <form>
        <p>
            <select asp-for="MovieGenre" asp-items="Model.Genres">
                <option value="">All</option>
            </select>
            Title: <input type="text" asp-for="SearchString" />
            <input type="submit" value="Filter" />
        </p>
    </form>
    
    <table class="table">
    
        <thead>
            <tr>
                <th>
                    @Html.DisplayNameFor(model => model.Movie[0].Title)
                </th>
                <th>
                    @Html.DisplayNameFor(model => model.Movie[0].ReleaseDate)
                </th>
                <th>
                    @Html.DisplayNameFor(model => model.Movie[0].Genre)
                </th>
                <th>
                    @Html.DisplayNameFor(model => model.Movie[0].Price)
                </th>
                <th>
                    @Html.DisplayNameFor(model => model.Movie[0].Rating)
                </th>
                <th></th>
            </tr>
        </thead>
        <tbody>
            @foreach (var item in Model.Movie)
            {
                <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-page="./Edit" asp-route-id="@item.ID">Edit</a> |
                        <a asp-page="./Details" asp-route-id="@item.ID">Details</a> |
                        <a asp-page="./Delete" asp-route-id="@item.ID">Delete</a>
                    </td>
                </tr>
            }
        </tbody>
    </table>
    
  3. 次のページを Rating フィールドで更新します。

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

SqlException: Invalid column name 'Rating'.

SqlException 例外が発生するのは、更新された Movie モデル クラスが、データベースの Movie テーブルのスキーマと異なるためです。 データベース テーブルに Rating 列はありません。

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

  1. Entity Framework に、新しいモデル クラス スキーマを使用してデータベースを自動的にドロップさせ、再作成させます。 この手法は、開発周期の早い段階で便利です。開発者はモデルとデータベース スキーマを一緒に短期間で発展させることができます。 これの欠点は、データベース内の既存のデータが失われることです。 実稼働データベースでこの方法は使用しないでください。 スキーマの変更時にデータベースを削除し、初期化子を使用して、データベースにテスト データを自動的にシードすることは、多くの場合、アプリケーションを開発する上で有益な方法となります。
  2. モデル クラスに一致するように、既存のデータベースのスキーマを明示的に変更します。 この手法の長所は、データが維持されることです。 この変更は手動で行うか、データベース変更スクリプトを作成して行います。
  3. Code First Migrations を使用して、データベース スキーマを更新します。

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

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

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

完成した SeedData.cs ファイルを参照してください。

ソリューションをビルドします。

評価フィールドの移行を追加する

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

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

    Add-Migration Rating
    Update-Database
    

Add-Migration コマンドにより、フレームワークに次の指示があります。

  • Movie モデルを、Movie データベースのスキーマと比較します。
  • データベース スキーマを新しいモデルに移行するコードを作成します。

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

Update-Database コマンドを使うと、データベースにスキーマ変更を適用し、既存のデータを保持するようにフレームワークに指示できます。

データベース内のすべてのレコードを削除すると、初期化子はデータベースにデータを初期投入し、Rating フィールドを追加します。 削除は、ブラウザーの削除リンクを使用するか、Sql Server Object Explorer (SSOX) から実行できます。

別のオプションとしては、データベースを削除してから、移行を使用することで、データベースを再作成することもできます。 SSOX 内でデータベースを削除するには:

  1. SSOX でデータベースを選択します。

  2. データベースを右クリックし、 [削除] を選択します。

  3. [既存の接続を閉じる] をチェックします。

  4. [OK] を選択します。

  5. PMC でデータベースを更新します。

    Update-Database
    

アプリを実行し、Rating フィールドでムービーを作成、編集、表示できることを確認します。 データベースがシード処理されない場合は、SeedData.Initialize メソッドでブレークポイントを設定します。

次のステップ

サンプル コードを表示またはダウンロードします (ダウンロード方法)。

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

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

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

  • データベースに __EFMigrationsHistory テーブルが追加され、データベースのスキーマが生成元のモデル クラスと同期しているかどうかが追跡されます。
  • モデル クラスがデータベースと同期されていない場合、EF から例外がスローされます。

スキーマとモデルが同期中であることが自動的に検証されるようにすると、整合性のないデータベース コードの問題を発見しやすくなります。

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

  1. Models/Movie.cs ファイルを開き、Rating プロパティを追加します。

    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; }
    }
    
  2. アプリをビルドします。

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

    @page
    @model RazorPagesMovie.Pages.Movies.IndexModel
    
    @{
        ViewData["Title"] = "Index";
    }
    
    <h1>Index</h1>
    
    <p>
        <a asp-page="Create">Create New</a>
    </p>
    
    <form>
        <p>
            <select asp-for="MovieGenre" asp-items="Model.Genres">
                <option value="">All</option>
            </select>
            Title: <input type="text" asp-for="SearchString" />
            <input type="submit" value="Filter" />
        </p>
    </form>
    
    <table class="table">
    
        <thead>
            <tr>
                <th>
                    @Html.DisplayNameFor(model => model.Movie[0].Title)
                </th>
                <th>
                    @Html.DisplayNameFor(model => model.Movie[0].ReleaseDate)
                </th>
                <th>
                    @Html.DisplayNameFor(model => model.Movie[0].Genre)
                </th>
                <th>
                    @Html.DisplayNameFor(model => model.Movie[0].Price)
                </th>
                <th>
                    @Html.DisplayNameFor(model => model.Movie[0].Rating)
                </th>
                <th></th>
            </tr>
        </thead>
        <tbody>
            @foreach (var item in Model.Movie)
            {
                <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-page="./Edit" asp-route-id="@item.ID">Edit</a> |
                        <a asp-page="./Details" asp-route-id="@item.ID">Details</a> |
                        <a asp-page="./Delete" asp-route-id="@item.ID">Delete</a>
                    </td>
                </tr>
            }
        </tbody>
    </table>
    
  4. 次のページを Rating フィールドで更新します。

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

SqlException: Invalid column name 'Rating'.

SqlException 例外が発生するのは、更新された Movie モデル クラスが、データベースの Movie テーブルのスキーマと異なるためです。 データベース テーブルに Rating 列はありません。

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

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

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

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

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

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

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

完成した SeedData.cs ファイルを参照してください。

ソリューションをビルドします。

評価フィールドの移行を追加する

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

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

    Add-Migration Rating
    Update-Database
    

Add-Migration コマンドにより、フレームワークに次の指示があります。

  • Movie モデルを、Movie データベースのスキーマと比較します。
  • データベース スキーマを新しいモデルに移行するコードを作成します。

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

Update-Database コマンドを使うと、データベースにスキーマ変更を適用し、既存のデータを保持するようにフレームワークに指示できます。

データベース内のすべてのレコードを削除すると、初期化子はデータベースにデータを初期投入し、Rating フィールドを追加します。 削除は、ブラウザーの削除リンクを使用するか、Sql Server Object Explorer (SSOX) から実行できます。

別のオプションとしては、データベースを削除してから、移行を使用することで、データベースを再作成することもできます。 SSOX 内でデータベースを削除するには:

  1. SSOX でデータベースを選択します。

  2. データベースを右クリックし、 [削除] を選択します。

  3. [既存の接続を閉じる] をチェックします。

  4. [OK] を選択します。

  5. PMC でデータベースを更新します。

    Update-Database
    

アプリを実行し、Rating フィールドでムービーを作成、編集、表示できることを確認します。 データベースがシード処理されない場合は、SeedData.Initialize メソッドでブレークポイントを設定します。

次のステップ

サンプル コードを表示またはダウンロードします (ダウンロード方法)。

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

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

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

  • データベースに __EFMigrationsHistory テーブルが追加され、データベースのスキーマが生成元のモデル クラスと同期しているかどうかが追跡されます。
  • モデル クラスがデータベースと同期されていない場合、EF から例外がスローされます。

スキーマとモデルが同期中であることが自動的に検証されるようにすると、整合性のないデータベース コードの問題を発見しやすくなります。

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

  1. Models/Movie.cs ファイルを開き、Rating プロパティを追加します。

    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; }
    }
    
  2. アプリをビルドします。

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

    @page
    @model RazorPagesMovie.Pages.Movies.IndexModel
    
    @{
        ViewData["Title"] = "Index";
    }
    
    <h1>Index</h1>
    
    <p>
        <a asp-page="Create">Create New</a>
    </p>
    
    <form>
        <p>
            <select asp-for="MovieGenre" asp-items="Model.Genres">
                <option value="">All</option>
            </select>
            Title: <input type="text" asp-for="SearchString" />
            <input type="submit" value="Filter" />
        </p>
    </form>
    
    <table class="table">
    
        <thead>
            <tr>
                <th>
                    @Html.DisplayNameFor(model => model.Movie[0].Title)
                </th>
                <th>
                    @Html.DisplayNameFor(model => model.Movie[0].ReleaseDate)
                </th>
                <th>
                    @Html.DisplayNameFor(model => model.Movie[0].Genre)
                </th>
                <th>
                    @Html.DisplayNameFor(model => model.Movie[0].Price)
                </th>
                <th>
                    @Html.DisplayNameFor(model => model.Movie[0].Rating)
                </th>
                <th></th>
            </tr>
        </thead>
        <tbody>
            @foreach (var item in Model.Movie)
            {
                <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-page="./Edit" asp-route-id="@item.ID">Edit</a> |
                        <a asp-page="./Details" asp-route-id="@item.ID">Details</a> |
                        <a asp-page="./Delete" asp-route-id="@item.ID">Delete</a>
                    </td>
                </tr>
            }
        </tbody>
    </table>
    
  4. 次のページを Rating フィールドで更新します。

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

SqlException: Invalid column name 'Rating'.

SqlException 例外が発生するのは、更新された Movie モデル クラスが、データベースの Movie テーブルのスキーマと異なるためです。 データベース テーブルに Rating 列はありません。

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

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

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

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

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

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

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

完成した SeedData.cs ファイルを参照してください。

ソリューションをビルドします。

評価フィールドの移行を追加する

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

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

    Add-Migration Rating
    Update-Database
    

Add-Migration コマンドにより、フレームワークに次の指示があります。

  • Movie モデルを、Movie データベースのスキーマと比較します。
  • データベース スキーマを新しいモデルに移行するコードを作成します。

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

Update-Database コマンドを使うと、データベースにスキーマ変更を適用し、既存のデータを保持するようにフレームワークに指示できます。

データベース内のすべてのレコードを削除すると、初期化子はデータベースにデータを初期投入し、Rating フィールドを追加します。 これはブラウザーの削除リンクで行うか、Sql Server Object Explorer (SSOX) から行うことができます。

別のオプションとしては、データベースを削除してから、移行を使用することで、データベースを再作成することもできます。 SSOX 内でデータベースを削除するには:

  • SSOX でデータベースを選択します。

  • データベースを右クリックし、 [削除] を選択します。

  • [既存の接続を閉じる] をチェックします。

  • [OK] を選択します。

  • PMC でデータベースを更新します。

    Update-Database
    

アプリを実行し、Rating フィールドでムービーを作成、編集、表示できることを確認します。 データベースがシード処理されない場合は、SeedData.Initialize メソッドでブレークポイントを設定します。

次のステップ