ASP.NET MVC 5 - 给电影表和模型添加新字段

简介:

在本节中,您将使用Entity Framework Code First来实现模型类上的操作。从而使得这些操作和变更,可以应用到数据库中。

默认情况下,就像您在之前的教程中所作的那样,使用 Entity Framework Code First自动创建一个数据库,Code First为数据库所添加的表,将帮助您跟踪数据库是否和从它生成的模型类是同步的。如果他们不是同步的,Entity Framework将抛出一个错误。这非常方便的在开发时就可以发现错误,否则您可能会在运行时才发现这个问题。

为对象模型的变更设置 Code First Migrations

从解决方案资源管理器中双击Movies.mdf,打开数据库工具, 在数据库工具 (数据库资源管理器、 服务器资源管理器或 SQL Server对象资源管理器),右键单击Movies.mdf,并选择删除

clip_image002

Build应用程序,以确保没有任何编译错误。

工具菜单上,单击库包管理器,然后点击程序包管理器控制台.

clip_image004

程序包管理器控制台窗口,在提示符 PM> 后输入:

Enable-Migrations -ContextTypeName MvcMovie.Models.MovieDBContext

clip_image006

如上所示的Enable-Migrations 命令,会在Migrations文件夹下创建一个Configuration.cs 文件。

clip_image008

在Visual Studio 里面打开Configuration.cs 文件. 用下面的代码替换Seed函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
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,并选择“解析(Resolve)”,然后单击“usingMvcMovie.Models;

clip_image010

这样做会增加下面的语句:

using MvcMovie.Models;

Code First Migrations调用Seed的方法,每个迁移(程序包管理器控制台更新数据库),此方法用于updates数据(如果数据存在),或inserted数据。

AddOrUpdate方法在下面的代码执行一个的“upsert”操作:

1
2
3
4
5
6
7
8
9
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   
     }

因为Seed方法与每个迁移同时运行时,故,你不能仅仅插入数据,因为当你正试图添加,可能已经完成了创建数据库后的第一次迁移。“upsert”操作阻止错误的发生,如果你尝试插入一个已经存在的行,它覆盖任何数据更改,当你在测试应用程序的同时。你可能不希望这样的事情发生:在某些情况下,当您更改数据测试时,你希望你的变化后数据库同步更新。在这种情况下,你想要做一个有条件的插入操作:只有当它不存在的时候,插入一行。     
传递给AddOrUpdate的方法的第一个参数, 指定的属性来使用以检查是否已存在某行。对于您所提供的测试影片的数据,Title属性可以被用于此目的,因为每个标题在列表中是唯一:

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

这个代码假设titiles属性是唯一的。如果手动添加一个重复的标题,你会得到下面的异常。    
Sequence contains more than one element
更多关于 AddOrUpdate 方法的信息,请参见 Take care with EF 4.3 AddOrUpdate Method..

 CTRL-SHIFT-B Build工程。(如果此次Build不成功,以下的步骤将会失败。)

下一步是创建一个DbMigration类,用于初始化数据库迁移。此迁移类将创建新的数据库,这也就是为什么在之前的步骤中你要删除movie.mdf文件。

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

clip_image012

Code First Migrations将会在Migrations文件夹中创建另一个类文件 (文件名为: {DateStamp}_Initial.cs ),此类中包含的代码将创建数据库的Schema。迁移文件名使用时间戳作为前缀,以帮助用来排序和查找。查看{DateStamp}_Initial.cs文件,它包含了为电影数据库创建电影表的说明。当您更新数据库时, {DateStamp}_Initial.cs文件将会被运行并创建 DB 的Schema。然后Seed方法将运行,用来填充 DB 的测试数据。

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

clip_image014

如果您收到表已经存在并且无法创建的错误,可能是因为您已经删除了数据库,并且在执行update-database之前,您运行了应用程序。在这种情况下,再次删除Movies.mdf文件,然后重试update-database命令。如果您仍遇到错误,删除Migration文件夹及其内容,然后从头开始重做。(即删除Movies.mdf文件,然后再进行Enable-Migrations)

运行该应用程序,然后浏览URL /Movies Seed数据显示如下:

clip_image016

为影片模型添加评级(Rating)属性

给现有的Movie类,添加新的Rating属性。打开Models\Movie.cs文件并添加如下Rating属性:

public string Rating { get; set; }

完整的Movie类如下:

1
2
3
4
5
6
7
8
9
10
11
12
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 ; }   
}

Build 应用程序 Build>Build Move或CTRL-SHIFT-B.

因为你已经添加了新的字段,电影类的,你还需要Bind,所以这次新的属性将被包含。更新的绑定属性,Create和Edit动作方法, 包括Rating属性:

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

您还需要更新视图模板,以显示浏览器视图中创建和编辑新的评级(Rating)属性。

打开\Views\Movies\Index.cshtml文件,在Price列后面添加<th>Rating</th>的列头。然后添加一个<td>列来显示@item.Rating的值。下面是更新的Index.cshtml视图模板:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
@model IEnumerable< MvcMovie.Models.Movie >  
@{   
     ViewBag.Title = "Index";   
}   
< h2 >Index</ h2 >   
     @Html.ActionLink("Create New", "Create")   
     @using (Html.BeginForm("Index", "Movies", FormMethod.Get))   
     {   
             
         Genre: @Html.DropDownList("movieGenre", "All")   
         Title: @Html.TextBox("SearchString")   
         < input  type = "submit"  value = "Filter"  />   
             
     }   
< 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 >

下一步,打开\Views\Movies\Create.cshtml文件,并在form标签结束处的附近添加如下代码。您可以在创建新的电影时指定一个电影等级。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
< 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)   
                 @Html.ValidationMessageFor(model => model.Price)   
             </ 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)   
                 @Html.ValidationMessageFor(model => model.Rating)   
             </ 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")   
}
        
< 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)
@Html.ValidationMessageFor(model => model.Price)
</ 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)
@Html.ValidationMessageFor(model => model.Rating)
</ 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。然而,当您这样做时,您将看到以下之一的错误信息:

clip_image018
自从数据库创建后,备份的'MovieDBContext上下文模型已经改变。请考虑使用Code First Migrations更新数据库 (http://go.microsoft.com/fwlink/?LinkId=238269).

clip_image020

你看到这个错误,因为更新的的Movie模型类中比现在Movie现有数据库表的schema不同。 (在数据库表中没有Rating列。)

有几个解决错误的方法:

1. Entity Framework会自动删除并重新创建数据库根据新模型类schema。在开发周期的早期, 这种方式非常方便,当你正在做开发一个测试数据库,它可以让你快速演进模型和数据库schema。不足之处,你将失去现有的数据库中的数据 - 所以对生产数据库你不想使用这种方法! 通常是一个富有成效的办法,开发一个应用程序来初始化数据库的自动测试数据。更多关于Entity Framework database初始化的信息,请参阅Tom Dykstra's fantastic ASP.NET MVC/Entity Framework tutorial.

2. 显式修改现有数据库的架构,以便它匹配的模型类。这种方法的优点是,你保持你的数据。可以使手动或通过建立数据库更改脚本实现它。

3. 使用Code First Migrations来更新数据库schema。

在本教程中,我们将使用Code First Migrations方法。

更新Seed 方法,以使它可以给新列提供一个值。 打开Migrations\Configuration.cs 文件,在每个Movie下添加Rating 字段.

1
2
3
4
5
6
7
8
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命令告诉migration framework,来检查当前电影模型与当前的影片 DB Schema并创建必要的代码以将数据库迁移到新的模型。AddRatingMig 是一个任意的文件名参数,用于命名migration文件。它将有助于使得迁移步骤成为一个有意义的名字。

当命令完成后,用Visual Studio 打开类文件,新继承自DbMIgration 类的定义,并在Up 方法中,您可以看到创建新列的代码:

1
2
3
4
5
6
7
8
9
10
11
12
public  partial  class  AddRatingMig : DbMigration  
{   
     public  override  void  Up()   
     {   
         AddColumn( "dbo.Movies" "Rating" , c => c.String());   
     }   
       
     public  override  void  Down()   
     {   
         DropColumn( "dbo.Movies" "Rating" );   
     }   
}

Build解决方案,然后在 程序包管理器控制台窗口中输入"update-database"命令。

下面的图片显示了 程序包管理器控制台窗口的输出 (日期戳前面添加的评级会有所不同)

clip_image022

重新运行应用程序,然后浏览 /Movies 的 URL。您可以看到新的评级字段。

clip_image024

单击CreateNew链接来添加一部新电影。注意,请您可以为电影添加评级。

clip_image026

单击Create。新的电影,包括评级,将显示在电影列表中:

clip_image028

该项目目前正在使用的迁移 (migrations),当你添加新的字段或更新数据库Schema, 你不需要删除数据库。在下一节中,我们将让更多的架构更改,并使用迁移来更新的数据库。

此外您也应该把Rating 字段添加到Edit、Details和Delete的视图模板中。

您可以再次在 程序包管理器控制台窗口中输入"update-database"命令,将不会有任何新的变化,因为数据库Schema 和模型类现在是匹配的。然而,运行“update-database”将运行再次Seed方法,如果你改变任何种子数据,更改都将丢失,因为Seed的方法upserts数据。你可以阅读更多关于Seed的方法Tom Dykstra's的流行的ASP.NET MVC/Entity Framework tutorial.。

在本节中,您看到了如何修改模型对象并始终保持其和数据库Schema的同步。您还学习了使用填充示例数据来创建新数据库的例子,您可以反复尝试。这只是一个简单的介绍Code First,更完整的教程的请参阅Creating an Entity Framework Data Model for an ASP.NET MVC Application。接下来,让我们看看如何将丰富的验证逻辑添加到模型类,并对模型类执行一些强制的业务规则验证。




本文转自 powertoolsteam 51CTO博客,原文链接:http://blog.51cto.com/powertoolsteam/1363659,如需转载请自行联系原作者

相关文章
|
7月前
|
存储 设计模式 前端开发
QTChart实现柱状图的mvc模型
QTChart实现柱状图的mvc模型
92 1
|
3月前
|
开发框架 前端开发 .NET
ASP.NET CORE 3.1 MVC“指定的网络名不再可用\企图在不存在的网络连接上进行操作”的问题解决过程
ASP.NET CORE 3.1 MVC“指定的网络名不再可用\企图在不存在的网络连接上进行操作”的问题解决过程
38 0
|
2天前
|
算法
r语言中对LASSO回归,Ridge岭回归和Elastic Net模型实现
r语言中对LASSO回归,Ridge岭回归和Elastic Net模型实现
10 1
|
9天前
|
机器学习/深度学习 数据挖掘 Go
中科院二区7.4分|NET基因肿瘤分型+生存预后模型+分子对接
在《Journal of Translational Medicine》上发表的最新研究中,科学家们鉴定了一种新的NET相关基因签名,用于预测弥漫性大B细胞淋巴瘤(DLBCL)患者的预后。他们发现8个基因(PARVB,LYZ,PPARGC1A,HIF1A,SPP1,CDH1,S100A9和CXCL2)与DLBCL生存率显著相关,建立了NRG遗传风险模型,该模型可能有助于指导DLBCL的治疗选择。研究包括基因表达数据的分析、预后特征的构建和验证,以及与免疫微环境和潜在治疗靶点的相关性探索。
16 0
|
29天前
|
开发框架 前端开发 .NET
进入ASP .net mvc的世界
进入ASP .net mvc的世界
28 0
|
29天前
mvc.net分页查询案例——mvc-paper.css
mvc.net分页查询案例——mvc-paper.css
5 0
|
1月前
|
设计模式 前端开发 数据处理
MVC架构中,控制器和模型之间是如何交互的
MVC架构中,控制器和模型之间是如何交互的
9 0
|
1月前
|
存储 设计模式 前端开发
请解释 Web 应用程序的 MVC(模型-视图-控制器)架构。
【2月更文挑战第26天】【2月更文挑战第89篇】请解释 Web 应用程序的 MVC(模型-视图-控制器)架构。
|
1月前
|
开发框架 前端开发 .NET
C# .NET面试系列六:ASP.NET MVC
<h2>ASP.NET MVC #### 1. MVC 中的 TempData\ViewBag\ViewData 区别? 在ASP.NET MVC中,TempData、ViewBag 和 ViewData 都是用于在控制器和视图之间传递数据的机制,但它们有一些区别。 <b>TempData:</b> 1、生命周期 ```c# TempData 的生命周期是短暂的,数据只在当前请求和下一次请求之间有效。一旦数据被读取,它就会被标记为已读,下一次请求时就会被清除。 ``` 2、用途 ```c# 主要用于在两个动作之间传递数据,例如在一个动作中设置 TempData,然后在重定向到另
95 5
|
2月前
|
机器学习/深度学习 编解码 并行计算
SegNetr来啦 | 超越UNeXit/U-Net/U-Net++/SegNet,精度更高模型更小的UNet家族
SegNetr来啦 | 超越UNeXit/U-Net/U-Net++/SegNet,精度更高模型更小的UNet家族
40 0