向电影模型和表添加新字段

作者: 里克·安德森

注意

此处提供了本教程的更新版本,它使用 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并选择“删除以删除电影数据库。

显示“服务器资源管理器”窗口的屏幕截图。“电影 D B 上下文”菜单中选择了“删除”。

导航回解决方案资源管理器。 右键单击Movies.mdf文件,然后选择“删除以删除电影数据库。

显示解决方案资源管理器窗口的屏幕截图。“电影点 m d f”右键单击菜单中选择了“删除”。

生成应用程序,以确保没有任何错误。

在“工具”菜单中,单击“NuGet 包管理器”,然后单击“包管理器控制台”

添加 Pack Man

提示符处的“程序包管理器控制台”窗口中PM>,输入“Enable-Migrations -ContextTypeName MvcMovie.Models.MovieDBContext”。

显示程序包管理器控制台窗口的屏幕截图。输入“启用迁移”命令。

Enable-Migrations 命令(如上所示)在新迁移文件夹中创建Configuration.cs文件。

显示解决方案资源管理器窗口的屏幕截图。迁移文件夹和 Configuration dot c 文件以红色圆圈。

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 迁移在 另一个类文件迁移文件夹(名称为 {DateStamp}_Initial.cs),此类包含创建数据库架构的代码。 迁移文件名以时间戳作为前缀,这样有助于排序。 检查 {DateStamp}_Initial.cs文件,其中包含为 Movie DB 创建 Movies 表的说明。 在以下说明中更新数据库时,此 {DateStamp}_Initial.cs 文件将运行并创建 DB 架构。 然后, Seed 方法将运行以使用测试数据填充 DB。

程序包管理器控制台中,输入命令“update-database”以创建数据库并运行 Seed 方法。

显示程序包管理器控制台窗口的屏幕截图。输入更新数据库命令。

如果收到一个错误,指出表已存在且无法创建,则可能是因为在删除数据库后以及执行 update-database之前运行了应用程序。 在这种情况下,请再次删除 Movies.mdf 文件,然后重试 update-database 该命令。 如果仍收到错误,请删除迁移文件夹和内容,然后从此页面顶部的说明开始(即删除 Movies.mdf 文件,然后继续启用迁移)。

运行应用程序并导航到 /Movies URL。 将显示种子数据。

显示包含四部电影列表的 M V C 电影索引页的屏幕截图。

向电影模型添加分级属性

首先向 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 列。)

可通过几种方法解决此错误:

  1. 让 Entity Framework 自动丢弃,并基于新的模型类架构重新创建数据库。 在测试数据库上执行活动开发时,此方法非常方便;它允许你快速改进模型和数据库架构。 不过,缺点是,在数据库中丢失现有数据,因此 你不想 在生产数据库中使用此方法! 使用初始值设定项自动为具有测试数据的数据库设定种子通常是开发应用程序的高效方法。 有关 Entity Framework 数据库初始值设定项的详细信息,请参阅 Tom Dykstra 的 ASP.NET MVC/Entity Framework 教程
  2. 对现有数据库架构进行显式修改,使它与模型类相匹配。 此方法的优点是可以保留数据。 可以手动或通过创建数据库更改脚本进行此更改。
  3. 使用 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。 可以看到新的“评分”字段。

显示“M V C 电影索引”页的屏幕截图,其中列出了四部电影。

单击“新建”链接添加新电影。 请注意,可以添加分级。

7_CreateRioII

单击 “创建” 。 新电影,包括评级,现在显示在电影列表:

7_ourNewMovie_SM

还应将 Rating 字段添加到“编辑”、“详细信息”和“SearchIndex”视图模板。

可以在程序包管理器控制台窗口中再次输入“update-database”命令,并且不会进行任何更改,因为架构与模型匹配。

本部分介绍了如何修改模型对象,并使数据库与更改保持同步。 你还了解了使用示例数据填充新创建的数据库的方法,以便可以试用方案。 接下来,让我们看看如何向模型类添加更丰富的验证逻辑,以及如何强制实施一些业务规则。