第 8 部分,将新字段添加到 ASP.NET Core MVC 应用Part 8, add a new field to an ASP.NET Core MVC app
作者:Rick AndersonBy Rick Anderson
在此部分中,Entity Framework Code First 迁移用于:In this section Entity Framework Code First Migrations is used to:
- 将新字段添加到模型。Add a new field to the model.
- 将新字段迁移到数据库。Migrate the new field to the database.
使用 EF Code First 自动创建数据库时,Code First 将:When EF Code First is used to automatically create a database, Code First:
- 将表添加到数据库,以跟踪数据库的架构。Adds a table to the database to track the schema of the database.
- 验证数据库与生成它的模型类是否同步。Verifies the database is in sync with the model classes it was generated from. 如果它们不同步,EF 则会引发异常。If they aren't in sync, EF throws an exception. 这使查找不一致的数据库/代码问题变得更加轻松。This makes it easier to find inconsistent database/code issues.
向电影模型添加分级属性Add a Rating Property to the Movie Model
将 Rating
属性添加到 Models/Movie.cs:Add a Rating
property to 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; }
}
}
生成应用Build the app
- Visual StudioVisual Studio
- Visual Studio CodeVisual Studio Code
- Visual Studio for MacVisual Studio for Mac
Ctrl+Shift+BCtrl+Shift+B
因为已经添加新字段到 Movie
类,所以需要更新属性绑定列表,将此新属性纳入其中。Because you've added a new field to the Movie
class, you need to update the property binding list so this new property will be included. 在 MoviesController.cs 中,更新 Create
和 Edit
操作方法的 [Bind]
属性,以包括 Rating
属性:In MoviesController.cs, update the [Bind]
attribute for both the Create
and Edit
action methods to include the Rating
property:
[Bind("Id,Title,ReleaseDate,Genre,Price,Rating")]
更新视图模板以在浏览器视图中显示、创建和编辑新的 Rating
属性。Update the view templates in order to display, create, and edit the new Rating
property in the browser view.
编辑 /Views/Movies/Index.cshtml 文件并添加 Rating
字段:Edit the /Views/Movies/Index.cshtml file and add a Rating
field:
<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>
<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>
使用 Rating
字段更新 /Views/Movies/Create.cshtml。Update the /Views/Movies/Create.cshtml with a Rating
field.
- Visual Studio / Visual Studio for MacVisual Studio / Visual Studio for Mac
- Visual Studio CodeVisual Studio Code
可以复制/粘贴之前的“窗体组”,并让 intelliSense 帮助更新字段。You can copy/paste the previous "form group" and let intelliSense help you update the fields. IntelliSense 适用于标记帮助程序。IntelliSense works with Tag Helpers.
更新剩余模板。Update the remaining templates.
更新 SeedData
类,使它提供新列的值。Update the SeedData
class so that it provides a value for the new column. 示例更改如下所示,但可能需要对每个 new Movie
做出此更改。A sample change is shown below, but you'll want to make this change for each new Movie
.
new Movie
{
Title = "When Harry Met Sally",
ReleaseDate = DateTime.Parse("1989-1-11"),
Genre = "Romantic Comedy",
Rating = "R",
Price = 7.99M
},
在 DB 更新为包括新字段之前,应用将不会正常工作。The app won't work until the DB is updated to include the new field. 如果它现在运行,将引发以下 SqlException
:If it's run now, the following SqlException
is thrown:
SqlException: Invalid column name 'Rating'.
发生此错误是因为更新的 Movie 模型类与现有数据库的 Movie 表架构不同。This error occurs because the updated Movie model class is different than the schema of the Movie table of the existing database. (数据库表中没有 Rating
列。)(There's no Rating
column in the database table.)
可通过几种方法解决此错误:There are a few approaches to resolving the error:
让 Entity Framework 自动丢弃,并基于新的模型类架构重新创建数据库。Have the Entity Framework automatically drop and re-create the database based on the new model class schema. 在测试数据库上进行开发时,此方法在开发周期早期很方便;通过它可以一起快速改进模型和数据库架构。This approach is very convenient early in the development cycle when you're doing active development on a test database; it allows you to quickly evolve the model and database schema together. 但其缺点是会丢失数据库中的现有数据 - 因此请勿对生产数据库使用此方法!The downside, though, is that you lose existing data in the database — so you don't want to use this approach on a production database! 使用初始值设定项,以使用测试数据自动设定数据库种子,这通常是开发应用程序的有效方式。Using an initializer to automatically seed a database with test data is often a productive way to develop an application. 对于早期开发和使用 SQLite 的情况,这是一个不错的方法。This is a good approach for early development and when using SQLite.
对现有数据库架构进行显式修改,使它与模型类相匹配。Explicitly modify the schema of the existing database so that it matches the model classes. 此方法的优点是可以保留数据。The advantage of this approach is that you keep your data. 可以手动或通过创建数据库更改脚本进行此更改。You can make this change either manually or by creating a database change script.
使用 Code First 迁移更新数据库架构。Use Code First Migrations to update the database schema.
对于本教程,请使用 Code First 迁移。For this tutorial, Code First Migrations is used.
- Visual StudioVisual Studio
- Visual Studio Code / Visual Studio for MacVisual Studio Code / Visual Studio for Mac
从“工具”菜单中,选择“NuGet 包管理器”>“包管理器控制台”。 From the Tools menu, select NuGet Package Manager > Package Manager Console.
在 PMC 中,输入以下命令:In the PMC, enter the following commands:
Add-Migration Rating
Update-Database
Add-Migration
命令会通知迁移框架使用当前 Movie
DB 架构检查当前 Movie
模型,并创建必要的代码,将 DB 迁移到新模型。The Add-Migration
command tells the migration framework to examine the current Movie
model with the current Movie
DB schema and create the necessary code to migrate the DB to the new model.
名称“Rating”是任意的,用于对迁移文件进行命名。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.
如果删除 DB 中的所有记录,初始化方法会设定 DB 种子,并将包括 Rating
字段。If all the records in the DB are deleted, the initialize method will seed the DB and include the Rating
field.
运行应用,并验证是否可以创建、编辑和显示具有 Rating
字段的电影。Run the app and verify you can create, edit, and display movies with a Rating
field.