向电影模型和表添加新字段
作者: 里克·安德森
注意
此处提供了本教程的更新版本,它使用 ASP.NET MVC 5 和 Visual Studio 2013。 它更安全,更易于遵循并演示更多功能。
在本部分中,你将使用Entity Framework Code First 迁移将一些更改迁移到模型类,以便将更改应用于数据库。
默认情况下,使用 Entity Framework Code First 自动创建数据库时,如本教程前面所述,Code First 向数据库添加一个表,以帮助跟踪数据库的架构是否与生成的模型类同步。 如果它们未同步,则 Entity Framework 将引发错误。 这样就可以更轻松地在开发时跟踪你可能只在运行时发现(通过模糊错误)的问题。
为模型更改设置Code First 迁移
如果使用 Visual Studio 2012,请双击解决方案资源管理器中的Movies.mdf文件以打开数据库工具。 Visual Studio Express for Web 将显示数据库资源管理器,Visual Studio 2012 将显示服务器资源管理器。 如果使用 Visual Studio 2010,请使用 SQL Server 对象资源管理器。
在数据库工具(数据库资源管理器、服务器资源管理器或 SQL Server 对象资源管理器),右键单击MovieDBContext
并选择“删除”以删除电影数据库。
导航回解决方案资源管理器。 右键单击Movies.mdf文件,然后选择“删除”以删除电影数据库。
生成应用程序,以确保没有任何错误。
在“工具”菜单中,单击“NuGet 包管理器”,然后单击“包管理器控制台”。
在提示符处的“程序包管理器控制台”窗口中PM>
,输入“Enable-Migrations -ContextTypeName MvcMovie.Models.MovieDBContext”。
Enable-Migrations 命令(如上所示)在新迁移文件夹中创建Configuration.cs文件。
Visual Studio 将打开 Configuration.cs 文件。 将 Seed
Configuration.cs 文件中的方法替换为以下代码:
protected override void Seed(MvcMovie.Models.MovieDBContext context)
{
context.Movies.AddOrUpdate( i => i.Title,
new Movie
{
Title = "When Harry Met Sally",
ReleaseDate = DateTime.Parse("1989-1-11"),
Genre = "Romantic Comedy",
Price = 7.99M
},
new Movie
{
Title = "Ghostbusters ",
ReleaseDate = DateTime.Parse("1984-3-13"),
Genre = "Comedy",
Price = 8.99M
},
new Movie
{
Title = "Ghostbusters 2",
ReleaseDate = DateTime.Parse("1986-2-23"),
Genre = "Comedy",
Price = 9.99M
},
new Movie
{
Title = "Rio Bravo",
ReleaseDate = DateTime.Parse("1959-4-15"),
Genre = "Western",
Price = 3.99M
}
);
}
右键单击下面的Movie
红色波浪线,然后选择“解决”,然后使用 MvcMovie.Models;
这样做会添加以下 using 语句:
using MvcMovie.Models;
注意
Code First 迁移每次迁移(即在 程序包管理器 控制台中调用 update-database)后调用Seed
该方法,此方法更新已插入的行,或者如果它们尚不存在,则将其插入。
按 Ctrl-Shift-B 生成项目。(如果此时未生成,以下步骤将失败。
下一步是为初始迁移创建 DbMigration
类。 此迁移会创建一个新数据库,这就是在上一步中删除 movie.mdf 文件的原因。
在“程序包管理器控制台”窗口中,输入命令“add-migration Initial”以创建初始迁移。 名称“Initial”是任意名称,用于命名创建的迁移文件。
Code First 迁移在
在程序包管理器控制台中,输入命令“update-database”以创建数据库并运行 Seed 方法。
如果收到一个错误,指出表已存在且无法创建,则可能是因为在删除数据库后以及执行 update-database
之前运行了应用程序。 在这种情况下,请再次删除 Movies.mdf 文件,然后重试 update-database
该命令。 如果仍收到错误,请删除迁移文件夹和内容,然后从此页面顶部的说明开始(即删除 Movies.mdf 文件,然后继续启用迁移)。
运行应用程序并导航到 /Movies URL。 将显示种子数据。
向电影模型添加分级属性
首先向 Rating
现有 Movie
类添加新属性。 打开 Models\Movie.cs 文件并添加Rating
如下所示的属性:
public string Rating { get; set; }
完整的 Movie
类现在类似于以下代码:
public class Movie
{
public int ID { get; set; }
public string Title { get; set; }
public DateTime ReleaseDate { get; set; }
public string Genre { get; set; }
public decimal Price { get; set; }
public string Rating { get; set; }
}
使用“生成电影”>菜单命令或按 Ctrl-SHIFT-B 生成应用程序。
更新类后Model
,还需要更新 \Views\Movies\Index.cshtml 和 \Views\Movies\Create.cshtml 视图模板,以便在浏览器视图中显示新Rating
属性。
打开\Views\Movies\Index.cshtml 文件,并在 Price 列后面添加列<th>Rating</th>
标题。 然后,在模板末尾附近添加一列 <td>
来呈现 @item.Rating
值。 下面是更新 的 Index.cshtml 视图模板如下所示:
@model IEnumerable<MvcMovie.Models.Movie>
@{
ViewBag.Title = "Index";
}
<h2>Index</h2>
<p>
@Html.ActionLink("Create New", "Create")
</p>
<table>
<tr>
<th>
@Html.DisplayNameFor(model => model.Title)
</th>
<th>
@Html.DisplayNameFor(model => model.ReleaseDate)
</th>
<th>
@Html.DisplayNameFor(model => model.Genre)
</th>
<th>
@Html.DisplayNameFor(model => model.Price)
</th>
<th>
@Html.DisplayNameFor(model => model.Rating)
</th>
<th></th>
</tr>
@foreach (var item in Model) {
<tr>
<td>
@Html.DisplayFor(modelItem => item.Title)
</td>
<td>
@Html.DisplayFor(modelItem => item.ReleaseDate)
</td>
<td>
@Html.DisplayFor(modelItem => item.Genre)
</td>
<td>
@Html.DisplayFor(modelItem => item.Price)
</td>
<td>
@Html.DisplayFor(modelItem => item.Rating)
</td>
<td>
@Html.ActionLink("Edit", "Edit", new { id=item.ID }) |
@Html.ActionLink("Details", "Details", new { id=item.ID }) |
@Html.ActionLink("Delete", "Delete", new { id=item.ID })
</td>
</tr>
}
</table>
接下来,打开 \Views\Movies\Create.cshtml 文件,并在窗体末尾附近添加以下标记。 这会呈现一个文本框,以便在创建新电影时指定分级。
<div class="editor-label">
@Html.LabelFor(model => model.Rating)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.Rating)
@Html.ValidationMessageFor(model => model.Rating)
</div>
现已更新应用程序代码以支持新 Rating
属性。
现在运行应用程序并导航到 /Movies URL。 不过,执行此操作时,会看到以下错误之一:
你会看到此错误,因为应用程序中更新 Movie
的模型类现在不同于现有数据库的表架构 Movie
。 (数据库表中没有 Rating
列。)
可通过几种方法解决此错误:
- 让 Entity Framework 自动丢弃,并基于新的模型类架构重新创建数据库。 在测试数据库上执行活动开发时,此方法非常方便;它允许你快速改进模型和数据库架构。 不过,缺点是,在数据库中丢失现有数据,因此 你不想 在生产数据库中使用此方法! 使用初始值设定项自动为具有测试数据的数据库设定种子通常是开发应用程序的高效方法。 有关 Entity Framework 数据库初始值设定项的详细信息,请参阅 Tom Dykstra 的 ASP.NET MVC/Entity Framework 教程。
- 对现有数据库架构进行显式修改,使它与模型类相匹配。 此方法的优点是可以保留数据。 可以手动或通过创建数据库更改脚本进行此更改。
- 使用 Code First 迁移更新数据库架构。
本教程使用 Code First 迁移。
更新 Seed 方法,以便为新列提供值。 打开 Migrations\Configuration.cs 文件,并将“评级”字段添加到每个 Movie 对象。
new Movie
{
Title = "When Harry Met Sally",
ReleaseDate = DateTime.Parse("1989-1-11"),
Genre = "Romantic Comedy",
Rating = "G",
Price = 7.99M
},
生成解决方案,然后打开程序包管理器控制台窗口并输入以下命令:
add-migration AddRatingMig
该 add-migration
命令告知迁移框架使用当前电影 DB 架构检查当前电影模型,并创建必要的代码将 DB 迁移到新模型。 AddRatingMig 是任意的,用于命名迁移文件。 对迁移步骤使用有意义的名称很有帮助。
此命令完成后,Visual Studio 将打开定义新 DbMigration
派生类的类文件,并在方法中 Up
可以看到创建新列的代码。
public partial class AddRatingMig : DbMigration
{
public override void Up()
{
AddColumn("dbo.Movies", "Rating", c => c.String());
}
public override void Down()
{
DropColumn("dbo.Movies", "Rating");
}
}
生成解决方案,然后在 程序包管理器“控制台”窗口中输入“update-database”命令。
下图显示了程序包管理器控制台窗口中的输出(AddRatingMig 之前的日期戳将有所不同)。
重新运行应用程序并导航到 /Movies URL。 可以看到新的“评分”字段。
单击“新建”链接添加新电影。 请注意,可以添加分级。
单击 “创建” 。 新电影,包括评级,现在显示在电影列表:
还应将 Rating
字段添加到“编辑”、“详细信息”和“SearchIndex”视图模板。
可以在程序包管理器控制台窗口中再次输入“update-database”命令,并且不会进行任何更改,因为架构与模型匹配。
本部分介绍了如何修改模型对象,并使数据库与更改保持同步。 你还了解了使用示例数据填充新创建的数据库的方法,以便可以试用方案。 接下来,让我们看看如何向模型类添加更丰富的验证逻辑,以及如何强制实施一些业务规则。