ASP.NET MVC 5 入门(09):添加新字段

原文:https://docs.microsoft.com/zh-cn/aspnet/mvc/overview/getting-started/introduction/adding-a-new-field

作者: Rick Anderson

ASP.NET MVC 5 入门

ASP.NET MVC 5 简介

此教程的更新版本可在此处使用最新版本的Visual Studio 新教程使用ASP.NET CORE MVC,这在本教程中提供了许多改进。

本教程介绍具有控制器和视图的 ASP.NET Core MVC。 Razor 页面是 ASP.NET Core 2.0 中的一个新选择,它是基于页面的编程模型,可以实现更简单、更高效地生成 Web UI。 建议先尝试 Razor 页面教程,再使用 MVC 版本。 Razor 页面教程:

  • 易于关注。
  • 涵盖更多功能。
  • 是开发新应用程序的首选方法。

以下教程系列介绍了GitHub上的 ASP.NET MVC: Source

在本节中,您将使用 Entity Framework Code First 迁移将某些更改迁移到模型类,以便将更改应用到数据库。

默认情况下,当你使用实体框架 Code First 来自动创建数据库时(如在本教程前面的步骤中所做的那样),Code First 将向数据库中添加一个表,以帮助跟踪数据库的架构是否与生成它的模型类的架构同步。 如果不同步,实体框架将引发错误。 这样就可以在开发时更轻松地跟踪问题,否则在运行时可能仅会发现(隐藏错误)。

一、设置模型更改的 Code First 迁移

导航到解决方案资源管理器。 右键单击 "电影 .mdf " 文件,然后选择 "删除" 以删除电影数据库。 如果看不到 "电影 .mdf " 文件,请单击红色框中显示的 "显示所有文件" 图标。

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

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

添加包手册

在 "包管理器控制台" 窗口中,在 PM> 提示符下输入

Enable-Migrations -ContextTypeName MvcMovie.Models.MovieDBContext

"启用-迁移" 命令(如上所示)在新的 "迁移" 文件夹中创建Configuration.cs文件。

Visual Studio 将打开Configuration.cs文件。 Configuration.cs文件中的 Seed 方法替换为以下代码:

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 下面的红色波浪线上,然后单击 "Show Potential Fixes,然后单击"使用 MvcMovie "。

这样做将添加以下 using 语句:

using MvcMovie.Models;

Note

Code First 迁移将在每次迁移后调用 Seed 方法(即,在包管理器控制台中调用更新数据库),此方法将更新已插入的行,如果它们尚不存在,则将其插入。

以下代码中的AddOrUpdate方法执行 "upsert" 操作:

context.Movies.AddOrUpdate(i => i.Title,
    new Movie
    {
        Title = "When Harry Met Sally",
        ReleaseDate = DateTime.Parse("1989-1-11"),
        Genre = "Romantic Comedy",
        Rating = "PG",
        Price = 7.99M
    }

由于种子方法随每个迁移一起运行,因此您不能只插入数据,因为在第一个创建数据库的迁移之后,您尝试添加的行将已存在。 如果尝试插入已存在的行,"upsert" 操作将会阻止发生的错误,但会覆盖在测试应用程序时对数据所做的任何更改。 对于某些表中的测试数据,您可能不希望发生这种情况:在某些情况下,当您在测试时更改数据时,您希望在数据库更新后更改保持不变。 在这种情况下,需要执行条件插入操作:仅在不存在行时插入行。

传递给AddOrUpdate方法的第一个参数指定要用于检查行是否已存在的属性。 对于所提供的测试电影数据,Title 属性可用于此目的,因为列表中的每个标题都是唯一的:

context.Movies.AddOrUpdate(i => i.Title,

此代码假设标题是唯一的。 如果手动添加重复标题,则在下次执行迁移时,将会出现以下异常。

序列包含多个元素

有关AddOrUpdate方法的详细信息,请参阅使用 EF 4.3 AddOrUpdate 方法

按 CTRL-SHIFT-B 生成项目。 (如果此时不生成,以下步骤将会失败。)

下一步是创建用于初始迁移的 DbMigration 类。 此迁移创建新的数据库,这就是在上一步中删除了movie .mdf文件的原因。

在 "程序包管理器控制台" 窗口中,输入命令 add-migration Initial 以创建初始迁移。 名称 "初始" 是任意名称,用于命名创建的迁移文件。

Code First 迁移在 "迁移" 文件夹(名称为 {日期戳}_Initial.cs )中创建另一个类文件,并且此类包含用于创建数据库架构的代码。 迁移文件名预先修复了时间戳,以帮助进行排序。 检查 {日期戳}_Initial.cs文件,其中包含为电影数据库创建 Movies 表的说明。 当你在下面的说明中更新数据库时,此 {日期戳}_Initial.cs文件将运行,并创建数据库架构。 然后, Seed方法将运行以用测试数据填充数据库。

在 "包管理器控制台" 中,输入用于创建数据库的命令 update-database,并运行 Seed 方法。

如果您收到一条错误消息,指示表已存在并且无法创建,则可能是您在删除数据库之后和执行 update-database之前运行了该应用程序。 在这种情况下,请再次删除电影 .mdf文件,然后重试 update-database 命令。 如果仍出现错误,请删除 "迁移" 文件夹和 "内容",然后从本页顶部的说明开始(删除 "",然后继续执行 "启用-迁移") 如果仍出现错误,请打开 SQL Server 对象资源管理器并从列表中删除数据库。

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

二、向电影模型添加分级属性

首先向现有 Movie 类添加新的 Rating 属性。 打开ModelsMovie.cs文件并添加 Rating 属性,如下所示:

public string Rating { get; set; }

完整的 Movie 类现在如以下代码所示:

public class Movie
{
    public int ID { get; set; }
    public string Title { get; set; }

    [Display(Name = "Release Date")]
    [DataType(DataType.Date)]
    [DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]
    public DateTime ReleaseDate { get; set; }
    public string Genre { get; set; }
    public decimal Price { get; set; }
    public string Rating { get; set; }
}

构建应用程序(Ctrl + Shift + B)。

由于已将新字段添加到 Movie 类,因此还需要更新 "绑定"允许列表,以便包括此新属性。 更新 CreateEdit 操作方法的 bind 属性,以包括 Rating 属性:

[Bind(Include = "ID,Title,ReleaseDate,Genre,Price,Rating")]

还需要更新视图模板,以便在浏览器视图中显示、创建和编辑新的 Rating 属性。

打开 " ViewsMoviesIndex.cshtml " 文件,然后在 " Price " 列之后添加 <th>Rating</th> 列标题。 然后,将 <td> 列添加到模板末尾附近,以呈现 @item.Rating 值。 更新后的索引 cshtml视图模板如下所示:

@model IEnumerable<MvcMovie.Models.Movie>
@{
    ViewBag.Title = "Index";
}
<h2>Index</h2>
<p>
    @Html.ActionLink("Create New", "Create")
    @using (Html.BeginForm("Index", "Movies", FormMethod.Get))
    {
    <p>
        Genre: @Html.DropDownList("movieGenre", "All")
        Title: @Html.TextBox("SearchString")
        <input type="submit" value="Filter" />
    </p>
    }
</p>
<table class="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>

接下来,打开 ViewsMoviesCreate.cshtml文件并添加 "Rating" 字段,其中包含以下突出显示的标记。 这将呈现一个文本框,以便您可以在创建新电影时指定级别。

<div class="form-group">
            @Html.LabelFor(model => model.Price, new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.Price, new { htmlAttributes = new { @class = "form-control" } })
                @Html.ValidationMessageFor(model => model.Price, "", new { @class = "text-danger" })
            </div>
        </div>

        <div class="form-group">
            @Html.LabelFor(model => model.Rating, new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.Rating, new { htmlAttributes = new { @class = "form-control" } })
                @Html.ValidationMessageFor(model => model.Rating, "", new { @class = "text-danger" })
            </div>
        </div>

        <div class="form-group">
            <div class="col-md-offset-2 col-md-10">
                <input type="submit" value="Create" class="btn btn-default" />
            </div>
        </div>
    </div>
}

<div>
    @Html.ActionLink("Back to List", "Index")
</div>

@section Scripts {
    @Scripts.Render("~/bundles/jqueryval")
}

现在,你已更新了应用程序代码,以支持新的 Rating 属性。

运行应用程序并导航到 /Movies URL。 不过,当你执行此操作时,你将看到以下错误之一:

创建数据库后,支持 "MovieDBContext" 上下文的模型已发生更改。 请考虑使用 Code First 迁移更新数据库( https://go.microsoft.com/fwlink/?LinkId=238269)。

出现此错误的原因是,应用程序中更新的 Movie 模型类现在与现有数据库的 Movie 表的架构不同。 (数据库表中没有 Rating 列。)

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

  1. 让 Entity Framework 自动丢弃,并基于新的模型类架构重新创建数据库。 在测试数据库上进行开发时,此方法在开发周期早期很方便;通过它可以一起快速改进模型和数据库架构。 不过,缺点在于丢失了数据库中的现有数据,因此希望在生产数据库上使用此方法! 使用初始值设定项,以使用测试数据自动设定数据库种子,这通常是开发应用程序的有效方式。 有关实体框架数据库初始值设定项的详细信息,请参阅ASP.NET MVC/实体框架教程
  2. 对现有数据库架构进行显式修改,使它与模型类相匹配。 此方法的优点是可以保留数据。 可以手动或通过创建数据库更改脚本进行此更改。
  3. 使用 Code First 迁移更新数据库架构。

本教程使用 Code First 迁移。

更新种子方法,使其为新列提供一个值。 打开 MigrationsConfiguration.cs 文件,并向每个电影对象添加分级字段。

new Movie
{
    Title = "When Harry Met Sally",
    ReleaseDate = DateTime.Parse("1989-1-11"),
    Genre = "Romantic Comedy",
    Rating = "PG",
    Price = 7.99M
},

生成解决方案,然后打开 "包管理器控制台" 窗口,并输入以下命令:

add-migration Rating

add-migration 命令通知迁移框架检查当前的电影模型和当前的 movie DB 架构,并创建必要的代码以将数据库迁移到新模型。 名称级别是任意的,用于对迁移文件进行命名。 为迁移步骤使用有意义的名称会很有帮助。

此命令完成后,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 命令。

下图显示了 "包管理器控制台" 窗口中的输出(预先计算评分的日期戳将有所不同)。

重新运行应用程序并导航到/Movies URL。 您可以看到新的 "分级" 字段。

单击 "新建" 链接以添加新电影。 请注意,可以添加级别。

7_CreateRioII

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

7_ourNewMovie_SM

现在,项目正在使用迁移,因此在添加新字段或更新架构时,无需删除数据库。 在下一部分中,我们将进行更多架构更改,并使用迁移来更新数据库。

还应将 "Rating" 字段添加到 "编辑"、"详细信息" 和 "删除" 视图模板。

您可以在 "包管理器控制台" 窗口中再次输入 "更新数据库" 命令,而不会运行任何迁移代码,因为该架构与该模型匹配。 但是,运行 "更新数据库" 将再次运行 Seed 方法,如果更改了任何种子数据,则这些更改将丢失,因为 Seed 方法 upsert 数据。 若要详细了解 Tom Dykstra 的热门ASP.NET MVC/实体框架教程中的 Seed 方法。

在本部分中,您将了解如何修改模型对象并使数据库与更改保持同步。 还了解了使用示例数据填充新创建的数据库的方法,以便可以试用方案。 这只是 Code First 的简要介绍,请参阅为ASP.NET MVC 应用程序创建实体框架数据模型,以获取有关主题的更完整教程。 接下来,让我们看看如何将更丰富的验证逻辑添加到模型类,并实现一些业务规则。

原文地址:https://www.cnblogs.com/springsnow/p/13264835.html