学习ASP .NET MVC5官方课程总结(九)添加新字段

学习ASP .NET MVC5官方教程总结(九)添加新字段

                            学习ASP .NET MVC5官方教程总结(九)添加新字段

       在本章中,我们将使用Entity Framework Code First 数据迁移功能将模型类的改变应用到数据库中。

       默认情况下,当我们使用Entity Framework Code First 自动创建一个数据库,像我们之前教程中讲的那样,Code First 添加一个table帮我们跟踪数据库结构是否与模型类同步。如果不同步,Entity Framework 将抛出一个错误,这样更方便我们在开发的时候发现问题,否则只能在运行时通过晦涩的错误来查找了。

   为模型更改设置 Code First 数据迁移

在解决方案资源管理器中,删除自动创建的 Movies.mdf 文件。

在工具菜单中,选择NuGet程序包管理器>程序包管理器控制台

学习ASP .NET MVC5官方课程总结(九)添加新字段

程序包管理器控制台窗口中输入:Enable-Migrations -ContextTypeName MvcMovie.Models.MovieDBContext

Enable-Migrations 命令创建了一个Migrations文件夹和Configuration.cs文件。

学习ASP .NET MVC5官方课程总结(九)添加新字段

打开 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       }
   );
}

使用这段代码的时候,需要添加 using MvcMovie.Models 的引用。

Code First 数据迁移在每次迁移(在程序包管理器控制台中调用 update-database)的时候都会调用Seed方法。

在进行下一步之前,先编译解决方案,否则下一步会出错误。

下一步,为初始化迁移创建一个 DbMigration 类。这次迁移创建一个新数据库,这也是我们为什么要删除之前的数据库的原因。

程序包管理器控制台窗口,输入命令 add-migration Initial  创建初始化迁移。名称Initial是随意命名的,它用来命名创建好的迁移文件。

学习ASP .NET MVC5官方课程总结(九)添加新字段

Code First Migrations 创建在Migrations文件夹中创建了一个文件(文件名是 {DateStamp}_Initial.cs ),这个类包含了创建数据库结构的代码。迁移文件的文件名以DateStamp开头是为了更好的排序,打开 {DateStamp}_Initial.cs  文件,它包含了为数据库MovieDB创建Movies表的指令。当你使用下面的命令更新数据库时,{DateStamp}_Initial.cs  文件将会运行并创建数据库结构,然后将执行 Seed 方法将测试数据插入数据库中。

程序包管理器控制台中输入命令 update-database 

学习ASP .NET MVC5官方课程总结(九)添加新字段

运行应用程序,浏览/Movies 地址,我们在Seed方法中添加的数据如下:

学习ASP .NET MVC5官方课程总结(九)添加新字段

    为Movie模型添加Rating字段

上面的内容一直在介绍如何进行数据迁移,现在开始为Movie类添加Rating字段,打开Movie.cs 文件,为它添加一个Rating字段,添加后的代码如下

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; }
        public decimal Price { get; set; }
        public string Rating { get; set; }
    }

编译解决方案。

现在我们已经更新了Movie类,你还需要修改\Views\Movies\Index.cshtml  和 \Views\Movies\Create.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") <br />
        <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>
    </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>

修改后的Create.cshtml

@model MvcMovie.Models.Movie
@{
    ViewBag.Title = "Create";
}
<h2>Create</h2>
@using (Html.BeginForm())
{
    @Html.AntiForgeryToken()
    @Html.ValidationSummary(true)

    <fieldset class="form-horizontal">
        <legend>Movie</legend>
        <div class="control-group">            
@Html.LabelFor(model => model.Title, new { @class = "control-label" })
            <div class="controls">                
@Html.EditorFor(model => model.Title)
  @Html.ValidationMessageFor(model => model.Title, null, new { @class = "help-inline" })
            </div>
        </div>

        <div class="control-group"> 
    @Html.LabelFor(model => model.ReleaseDate, new { @class = "control-label" })
            <div class="controls">              
  @Html.EditorFor(model => model.ReleaseDate)
          @Html.ValidationMessageFor(model => model.ReleaseDate, null, new { @class = "help-inline" })
            </div>
        </div>

        <div class="control-group">            
@Html.LabelFor(model => model.Genre, new { @class = "control-label" })
            <div class="controls">               
 @Html.EditorFor(model => model.Genre)
 @Html.ValidationMessageFor(model => model.Genre, null, new { @class = "help-inline" })
            </div>
        </div>

        <div class="control-group">            
@Html.LabelFor(model => model.Price, new { @class = "control-label" })
            <div class="controls">                
@Html.EditorFor(model => model.Price)
                @Html.ValidationMessageFor(model => model.Price, null, new { @class = "help-inline" })
            </div>
        </div>

        <div class="control-group">            
@Html.LabelFor(model => model.Rating, new { @class = "control-label" })
            <div class="controls">                
@Html.EditorFor(model => model.Rating)
  @Html.ValidationMessageFor(model => model.Rating, null, new { @class = "help-inline" })
            </div>
        </div>
        <div class="form-actions no-color">
            <input type="submit" value="Create" class="btn" />
        </div>
    </fieldset>}
<div>    @Html.ActionLink("Back to List", "Index")
</div>
@section Scripts {
    @Scripts.Render("~/bundles/jqueryval")
}

现在我们已经在程序中为Rating字段做成了修改。再次运行程序,浏览/movies 地址,这时我们会得到一个错误:

学习ASP .NET MVC5官方课程总结(九)添加新字段

出现这个错误的原因是Movie模型类发生了变化,而与它对应的数据表 Movie 中并不存在Rating字段。

解决这个问题有以下几种途径:

l 让Entity Framework自动删除并根据新的模型自动创建数据库。这种方式在早起开发过程中的测试数据库中非常方便,它可以快速的修改模型和数据库结构。另一方面,这样做将会使你丢失已有的数据,因此这种方式不能用在生产环境的数据库中。

2 在数据库中加上Rating字段,使数据库和Model类的结构相同。这种方式的优点是能够保留数据,你可以手动修改或使用数据库脚本修改。

3 使用Code First 迁移来升级数据库结构。

在本章中,我们使用Code First 迁移。

更新Seed 方法,使它为Rating字段提供一个值。

打开 Migrations\Configuration.cs 文件,为每一个Movie对象的Rating字段赋值。

修改后的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",
                    Rating = "PG",
                    Price = 7.99M
                },
                 new Movie
                 {
                     Title = "Ghostbusters ",
                     ReleaseDate = DateTime.Parse("1984-3-13"),
                     Genre = "Comedy",
                     Rating = "PG",
                     Price = 8.99M
                 },
                 new Movie
                 {
                     Title = "Ghostbusters 2",
                     ReleaseDate = DateTime.Parse("1986-2-23"),
                     Genre = "Comedy",
                     Rating = "PG",
                     Price = 9.99M
                 },
               new Movie
               {
                   Title = "Rio Bravo",
                   ReleaseDate = DateTime.Parse("1959-4-15"),
                   Genre = "Western",
                   Rating = "PG",
                   Price = 3.99M
               }
           );
        }

重新编译解决方案,然后打开程序包管理器控制台,执行命令:add-migration Rating

add-migration 命令告诉迁移程序去检查当前的Movie模型与当前数据库之间的差异,创建迁移数据库到最新模型的代码。名称 Rating 是可以随便命名的,此处用来命名迁移文件。

当命令执行完成之后,Visual Studio 会打开刚刚添加的继承自 DbMigration 的类文件,文件中有两个方法 UpDown,分别用来升级和降级数据库。在Up方法中我们可以看到为数据库添加列的代码,而Down方法中的代码则是删除Rating列。

namespace MvcMovie.Migrations
{
    using System;
    using System.Data.Entity.Migrations;
    
    public partial class Rating : DbMigration
    {
        public override void Up()
        {
            AddColumn("dbo.Movies", "Rating", c => c.String());
        }
        
        public override void Down()
        {
            DropColumn("dbo.Movies", "Rating");
        }
    }
}

编译解决方案,然后执行命令 update-database 

运行页面,你能看到已经加入了Rating字段:

学习ASP .NET MVC5官方课程总结(九)添加新字段

现在,通过项目中使用数据迁移,我们在添加字段或更新模型结构的时候不用再删除数据库了。在下一章中,我们将对结构做出更多的更改,并使用数据迁移来更新数据库。