Muokkaa

Jaa


Part 7, add a new field to a Razor Page in ASP.NET Core

Note

This isn't the latest version of this article. For the current release, see the .NET 9 version of this article.

Warning

This version of ASP.NET Core is no longer supported. For more information, see the .NET and .NET Core Support Policy. For the current release, see the .NET 9 version of this article.

Important

This information relates to a pre-release product that may be substantially modified before it's commercially released. Microsoft makes no warranties, express or implied, with respect to the information provided here.

For the current release, see the .NET 9 version of this article.

By Rick Anderson

In this section Entity Framework Core (EF Core) is used to define the database schema based on the app's model class:

  • Add a new field to the model.
  • Migrate the new field schema change to the database.

The EF Core approach allows for a more agile development process. The developer works on the app's data model directly while the database schema is created and then syncronized, all without the developer having to switch contexts to and from a datbase management tool. For an overview of Entity Framework Core and its benefits, see Entity Framework Core.

Using EF Code to automatically create and track a database:

  • Adds an __EFMigrationsHistory table to the database to track whether the schema of the database is in sync with the model classes it was generated from.
  • Throws an exception if the model classes aren't in sync with the database.

Automatic verification that the schema and model are in sync makes it easier to find inconsistent database code issues.

Adding a Rating Property to the Movie Model

  1. Open the Models/Movie.cs file and add a Rating property:

    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. Edit Pages/Movies/Index.cshtml, and add a Rating field:

    @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>
            <label>Title: <input type="text" asp-for="SearchString" /></label>
            <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. Update the following pages with a Rating field:

The app won't work until the database is updated to include the new field. Running the app without an update to the database throws a SqlException:

SqlException: Invalid column name 'Rating'.

The SqlException exception is caused by the updated Movie model class being different than the schema of the Movie table of the database. There's no Rating column in the database table.

There are a few approaches to resolving the error:

  1. Have the Entity Framework automatically drop and re-create the database using the new model class schema. This approach is convenient early in the development cycle, it allows developers to quickly evolve the model and database schema together. The downside is that existing data in the database is lost. Don't use this approach on a production database! Dropping the database on schema changes and using an initializer to automatically seed the database with test data is often a productive way to develop an app.
  2. Explicitly modify the schema of the existing database so that it matches the model classes. The advantage of this approach is to keep the data. Make this change either manually or by creating a database change script.
  3. Use EF Core Migrations to update the database schema.

For this tutorial, use EF Core Migrations.

Update the SeedData class so that it provides a value for the new column. A sample change is shown below, but make this change for each new Movie block.

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

See the completed SeedData.cs file.

Build the app

Press Ctrl+Shift+B

Add a migration for the rating field

  1. From the Tools menu, select NuGet Package Manager > Package Manager Console.

  2. In the Package Manager Console (PMC), enter the following command:

    Add-Migration Rating
    

The Add-Migration command tells the framework to:

  • Compare the Movie model with the Movie database schema.
  • Create code to migrate the database schema to the new model.

The name "Rating" is arbitrary and is used to name the migration file. It's helpful to use a meaningful name for the migration file.

  1. In the PMC, enter the following command:

    Update-Database
    

The Update-Database command tells the framework to apply the schema changes to the database and to preserve existing data.

Delete all the records in the database, the initializer will seed the database and include the Rating field. Deleting can be done with the delete links in the browser or from Sql Server Object Explorer (SSOX).

Another option is to delete the database and use migrations to re-create the database. To delete the database in SSOX:

  1. Select the database in SSOX.

  2. Right-click on the database, and select Delete.

  3. Check Close existing connections.

  4. Select OK.

  5. In the PMC, update the database:

    Update-Database
    

Run the app and verify you can create, edit, and display movies with a Rating field. If the database isn't seeded, set a break point in the SeedData.Initialize method.

Next steps

In this section Entity Framework Code First Migrations is used to:

  • Add a new field to the model.
  • Migrate the new field schema change to the database.

When using EF Code First to automatically create and track a database, Code First:

  • Adds an __EFMigrationsHistory table to the database to track whether the schema of the database is in sync with the model classes it was generated from.
  • Throws an exception if the model classes aren't in sync with the database.

Automatic verification that the schema and model are in sync makes it easier to find inconsistent database code issues.

Adding a Rating Property to the Movie Model

  1. Open the Models/Movie.cs file and add a Rating property:

    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. Edit Pages/Movies/Index.cshtml, and add a Rating field:

    @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>
            <label>Title: <input type="text" asp-for="SearchString" /></label>
            <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. Update the following pages with a Rating field:

The app won't work until the database is updated to include the new field. Running the app without an update to the database throws a SqlException:

SqlException: Invalid column name 'Rating'.

The SqlException exception is caused by the updated Movie model class being different than the schema of the Movie table of the database. There's no Rating column in the database table.

There are a few approaches to resolving the error:

  1. Have the Entity Framework automatically drop and re-create the database using the new model class schema. This approach is convenient early in the development cycle, it allows developers to quickly evolve the model and database schema together. The downside is that existing data in the database is lost. Don't use this approach on a production database! Dropping the database on schema changes and using an initializer to automatically seed the database with test data is often a productive way to develop an app.
  2. Explicitly modify the schema of the existing database so that it matches the model classes. The advantage of this approach is to keep the data. Make this change either manually or by creating a database change script.
  3. Use Code First Migrations to update the database schema.

For this tutorial, use Code First Migrations.

Update the SeedData class so that it provides a value for the new column. A sample change is shown below, but make this change for each new Movie block.

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

See the completed SeedData.cs file.

Build the app

Press Ctrl+Shift+B

Add a migration for the rating field

  1. From the Tools menu, select NuGet Package Manager > Package Manager Console.

  2. In the PMC, enter the following commands:

    Add-Migration Rating
    Update-Database
    

The Add-Migration command tells the framework to:

  • Compare the Movie model with the Movie database schema.
  • Create code to migrate the database schema to the new model.

The name "Rating" is arbitrary and is used to name the migration file. It's helpful to use a meaningful name for the migration file.

The Update-Database command tells the framework to apply the schema changes to the database and to preserve existing data.

Delete all the records in the database, the initializer will seed the database and include the Rating field. Deleting can be done with the delete links in the browser or from Sql Server Object Explorer (SSOX).

Another option is to delete the database and use migrations to re-create the database. To delete the database in SSOX:

  1. Select the database in SSOX.

  2. Right-click on the database, and select Delete.

  3. Check Close existing connections.

  4. Select OK.

  5. In the PMC, update the database:

    Update-Database
    

Run the app and verify you can create, edit, and display movies with a Rating field. If the database isn't seeded, set a break point in the SeedData.Initialize method.

Next steps

In this section Entity Framework Code First Migrations is used to:

  • Add a new field to the model.
  • Migrate the new field schema change to the database.

When using EF Code First to automatically create and track a database, Code First:

  • Adds an __EFMigrationsHistory table to the database to track whether the schema of the database is in sync with the model classes it was generated from.
  • Throws an exception if the model classes aren't in sync with the database.

Automatic verification that the schema and model are in sync makes it easier to find inconsistent database code issues.

Adding a Rating Property to the Movie Model

  1. Open the Models/Movie.cs file and add a Rating property:

    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. Edit Pages/Movies/Index.cshtml, and add a Rating field:

    @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>
            <label>Title: <input type="text" asp-for="SearchString" /></label>
            <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. Update the following pages with a Rating field:

The app won't work until the database is updated to include the new field. Running the app without an update to the database throws a SqlException:

SqlException: Invalid column name 'Rating'.

The SqlException exception is caused by the updated Movie model class being different than the schema of the Movie table of the database. There's no Rating column in the database table.

There are a few approaches to resolving the error:

  1. Have the Entity Framework automatically drop and re-create the database using the new model class schema. This approach is convenient early in the development cycle, it allows developers to quickly evolve the model and database schema together. The downside is that existing data in the database is lost. Don't use this approach on a production database! Dropping the database on schema changes and using an initializer to automatically seed the database with test data is often a productive way to develop an app.
  2. Explicitly modify the schema of the existing database so that it matches the model classes. The advantage of this approach is to keep the data. Make this change either manually or by creating a database change script.
  3. Use Code First Migrations to update the database schema.

For this tutorial, use Code First Migrations.

Update the SeedData class so that it provides a value for the new column. A sample change is shown below, but make this change for each new Movie block.

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

See the completed SeedData.cs file.

Build the app

Press Ctrl+Shift+B

Add a migration for the rating field

  1. From the Tools menu, select NuGet Package Manager > Package Manager Console.

  2. In the PMC, enter the following commands:

    Add-Migration Rating
    Update-Database
    

The Add-Migration command tells the framework to:

  • Compare the Movie model with the Movie database schema.
  • Create code to migrate the database schema to the new model.

The name "Rating" is arbitrary and is used to name the migration file. It's helpful to use a meaningful name for the migration file.

The Update-Database command tells the framework to apply the schema changes to the database and to preserve existing data.

Delete all the records in the database, the initializer will seed the database and include the Rating field. Deleting can be done with the delete links in the browser or from Sql Server Object Explorer (SSOX).

Another option is to delete the database and use migrations to re-create the database. To delete the database in SSOX:

  1. Select the database in SSOX.

  2. Right-click on the database, and select Delete.

  3. Check Close existing connections.

  4. Select OK.

  5. In the PMC, update the database:

    Update-Database
    

Run the app and verify you can create, edit, and display movies with a Rating field. If the database isn't seeded, set a break point in the SeedData.Initialize method.

Next steps

In this section Entity Framework Code First Migrations is used to:

  • Add a new field to the model.
  • Migrate the new field schema change to the database.

When using EF Code First to automatically create and track a database, Code First:

  • Adds an __EFMigrationsHistory table to the database to track whether the schema of the database is in sync with the model classes it was generated from.
  • Throws an exception if the model classes aren't in sync with the database.

Automatic verification that the schema and model are in sync makes it easier to find inconsistent database code issues.

Adding a Rating Property to the Movie Model

  1. Open the Models/Movie.cs file and add a Rating property:

    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. Edit Pages/Movies/Index.cshtml, and add a Rating field:

    @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>
            <label>Title: <input type="text" asp-for="SearchString" /></label>
            <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. Update the following pages with a Rating field:

The app won't work until the database is updated to include the new field. Running the app without an update to the database throws a SqlException:

SqlException: Invalid column name 'Rating'.

The SqlException exception is caused by the updated Movie model class being different than the schema of the Movie table of the database. There's no Rating column in the database table.

There are a few approaches to resolving the error:

  1. Have the Entity Framework automatically drop and re-create the database using the new model class schema. This approach is convenient early in the development cycle, it allows developers to quickly evolve the model and database schema together. The downside is that existing data in the database is lost. Don't use this approach on a production database! Dropping the database on schema changes and using an initializer to automatically seed the database with test data is often a productive way to develop an app.
  2. Explicitly modify the schema of the existing database so that it matches the model classes. The advantage of this approach is to keep the data. Make this change either manually or by creating a database change script.
  3. Use Code First Migrations to update the database schema.

For this tutorial, use Code First Migrations.

Update the SeedData class so that it provides a value for the new column. A sample change is shown below, but make this change for each new Movie block.

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

See the completed SeedData.cs file.

Build the solution.

Add a migration for the rating field

  1. From the Tools menu, select NuGet Package Manager > Package Manager Console.

  2. In the PMC, enter the following commands:

    Add-Migration Rating
    Update-Database
    

The Add-Migration command tells the framework to:

  • Compare the Movie model with the Movie database schema.
  • Create code to migrate the database schema to the new model.

The name "Rating" is arbitrary and is used to name the migration file. It's helpful to use a meaningful name for the migration file.

The Update-Database command tells the framework to apply the schema changes to the database and to preserve existing data.

Delete all the records in the database, the initializer will seed the database and include the Rating field. Deleting can be done with the delete links in the browser or from Sql Server Object Explorer (SSOX).

Another option is to delete the database and use migrations to re-create the database. To delete the database in SSOX:

  1. Select the database in SSOX.

  2. Right-click on the database, and select Delete.

  3. Check Close existing connections.

  4. Select OK.

  5. In the PMC, update the database:

    Update-Database
    

Run the app and verify you can create, edit, and display movies with a Rating field. If the database isn't seeded, set a break point in the SeedData.Initialize method.

Next steps

View or download sample code (how to download).

In this section Entity Framework Code First Migrations is used to:

  • Add a new field to the model.
  • Migrate the new field schema change to the database.

When using EF Code First to automatically create a database, Code First:

  • Adds an __EFMigrationsHistory table to the database to track whether the schema of the database is in sync with the model classes it was generated from.
  • If the model classes aren't in sync with the database, EF throws an exception.

Automatic verification that the schema and model are in sync makes it easier to find inconsistent database code issues.

Adding a Rating Property to the Movie Model

  1. Open the Models/Movie.cs file and add a Rating property:

    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. Build the app.

  3. Edit Pages/Movies/Index.cshtml, and add a Rating field:

    @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>
            <label>Title: <input type="text" asp-for="SearchString" /></label>
            <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. Update the following pages with a Rating field:

The app won't work until the database is updated to include the new field. Running the app without an update to the database throws a SqlException:

SqlException: Invalid column name 'Rating'.

The SqlException exception is caused by the updated Movie model class being different than the schema of the Movie table of the database. There's no Rating column in the database table.

There are a few approaches to resolving the error:

  1. Have the Entity Framework automatically drop and re-create the database using the new model class schema. This approach is convenient early in the development cycle, it allows you to quickly evolve the model and database schema together. The downside is that you lose existing data in the database. Don't use this approach on a production database! Dropping the database on schema changes and using an initializer to automatically seed the database with test data is often a productive way to develop an app.

  2. Explicitly modify the schema of the existing database so that it matches the model classes. The advantage of this approach is to keep the data. Make this change either manually or by creating a database change script.

  3. Use Code First Migrations to update the database schema.

For this tutorial, use Code First Migrations.

Update the SeedData class so that it provides a value for the new column. A sample change is shown below, but make this change for each new Movie block.

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

See the completed SeedData.cs file.

Build the solution.

Add a migration for the rating field

  1. From the Tools menu, select NuGet Package Manager > Package Manager Console.

  2. In the PMC, enter the following commands:

    Add-Migration Rating
    Update-Database
    

The Add-Migration command tells the framework to:

  • Compare the Movie model with the Movie database schema.
  • Create code to migrate the database schema to the new model.

The name "Rating" is arbitrary and is used to name the migration file. It's helpful to use a meaningful name for the migration file.

The Update-Database command tells the framework to apply the schema changes to the database and to preserve existing data.

Delete all the records in the database, the initializer will seed the database and include the Rating field. Deleting can be done with the delete links in the browser or from Sql Server Object Explorer (SSOX).

Another option is to delete the database and use migrations to re-create the database. To delete the database in SSOX:

  1. Select the database in SSOX.

  2. Right-click on the database, and select Delete.

  3. Check Close existing connections.

  4. Select OK.

  5. In the PMC, update the database:

    Update-Database
    

Run the app and verify you can create/edit/display movies with a Rating field. If the database isn't seeded, set a break point in the SeedData.Initialize method.

Next steps

View or download sample code (how to download).

In this section Entity Framework Code First Migrations is used to:

  • Add a new field to the model.
  • Migrate the new field schema change to the database.

When using EF Code First to automatically create a database, Code First:

  • Adds an __EFMigrationsHistory table to the database to track whether the schema of the database is in sync with the model classes it was generated from.
  • If the model classes aren't in sync with the database, EF throws an exception.

Automatic verification that the schema and model are in sync makes it easier to find inconsistent database code issues.

Adding a Rating Property to the Movie Model

  1. Open the Models/Movie.cs file and add a Rating property:

    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. Build the app.

  3. Edit Pages/Movies/Index.cshtml, and add a Rating field:

    @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>
            <label>Title: <input type="text" asp-for="SearchString" /></label>
            <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. Update the following pages with a Rating field:

The app won't work until the database is updated to include the new field. Running the app without an update to the database throws a SqlException:

SqlException: Invalid column name 'Rating'.

The SqlException exception is caused by the updated Movie model class being different than the schema of the Movie table of the database. There's no Rating column in the database table.

There are a few approaches to resolving the error:

  1. Have the Entity Framework automatically drop and re-create the database using the new model class schema. This approach is convenient early in the development cycle, it allows you to quickly evolve the model and database schema together. The downside is that you lose existing data in the database. Don't use this approach on a production database! Dropping the database on schema changes and using an initializer to automatically seed the database with test data is often a productive way to develop an app.

  2. Explicitly modify the schema of the existing database so that it matches the model classes. The advantage of this approach is to keep the data. Make this change either manually or by creating a database change script.

  3. Use Code First Migrations to update the database schema.

For this tutorial, use Code First Migrations.

Update the SeedData class so that it provides a value for the new column. A sample change is shown below, but make this change for each new Movie block.

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

See the completed SeedData.cs file.

Build the solution.

Add a migration for the rating field

  1. From the Tools menu, select NuGet Package Manager > Package Manager Console.

  2. In the PMC, enter the following commands:

    Add-Migration Rating
    Update-Database
    

The Add-Migration command tells the framework to:

  • Compare the Movie model with the Movie database schema.
  • Create code to migrate the database schema to the new model.

The name "Rating" is arbitrary and is used to name the migration file. It's helpful to use a meaningful name for the migration file.

The Update-Database command tells the framework to apply the schema changes to the database and to preserve existing data.

If you delete all the records in the database, the initializer will seed the database and include the Rating field. You can do this with the delete links in the browser or from Sql Server Object Explorer (SSOX).

Another option is to delete the database and use migrations to re-create the database. To delete the database in SSOX:

  • Select the database in SSOX.

  • Right-click on the database, and select Delete.

  • Check Close existing connections.

  • Select OK.

  • In the PMC, update the database:

    Update-Database
    

Run the app and verify you can create/edit/display movies with a Rating field. If the database isn't seeded, set a break point in the SeedData.Initialize method.

Next steps