原文链接:
接下来,我们将使用Entity Framework Code First Migrations,来对模型类的改变做数据迁移,而数据库能相应改变。
默认情况下,当你使用EF Code First自动生成数据库时,Code First添加了一个数据库来跟踪数据库和模型类的同步状况。如果它们不同步,EF会抛出一个异常。
一、添加Search动作和视图
我们将添加一个SerachIndex动作,能够通过类别或名字搜索电影,网址为MoviesSearchIndexURL。
1.显示SearchIndex表单
在Movies控制器中,添加SearchIndex()动作。
public ActionResult SearchIndex(string searchString) { var movies = from m in db.Movies select m; if (!String.IsNullOrEmpty(searchString)) { movies = movies.Where(s => s.Title.Contains(searchString)); } return View(movies); }
s=>s.Title是一个Lambda表达式。
在SearchIndex()动作中右击“添加视图”。
@model IEnumerable<MvcMovie.Models.Movie> @{ ViewBag.Title = "SearchIndex"; } <h2>SearchIndex</h2> <p> @Html.ActionLink("Create New", "Create") </p> <table> <tr> <th> Title </th> <th> ReleaseDate </th> <th> Genre </th> <th> Price </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.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>
运行应用程序,导航至/Movies/SearchIndex?searchString=ghost网址。
然而不可能希望用户每次通过路由来搜索电影,现在我们将在SearchIndex视图中添加搜索文本框,就在@Html.ActionLink("Create New", "Create")
后面。
@model IEnumerable<MvcMovie.Models.Movie> @{ ViewBag.Title = "SearchIndex"; } <h2>SearchIndex</h2> <p> @Html.ActionLink("Create New", "Create") @using (Html.BeginForm()){ <p> Title: @Html.TextBox("SearchString") <br /> <input type="submit" value="Filter" /></p> } </p>
运行应用程序,使用搜索电影功能。
2.添加按类型搜索
修改该Movies控制器中SearchIndex动作。
public ActionResult SearchIndex(string movieGenre, string searchString) { var GenreLst = new List<string>(); var GenreQry = from d in db.Movies orderby d.Genre select d.Genre; GenreLst.AddRange(GenreQry.Distinct()); ViewBag.movieGenre = new SelectList(GenreLst); var movies = from m in db.Movies select m; if (!String.IsNullOrEmpty(searchString)) { movies = movies.Where(s => s.Title.Contains(searchString)); } if (string.IsNullOrEmpty(movieGenre)) return View(movies); else { return View(movies.Where(x => x.Genre == movieGenre)); } }
修改SearchIndex视图,添加一个Html.DropDownList来显示类别。
<p> @Html.ActionLink("Create New", "Create") @using (Html.BeginForm("SearchIndex","Movies",FormMethod.Get)){ <p>Genre: @Html.DropDownList("movieGenre", "All") Title: @Html.TextBox("SearchString") <input type="submit" value="Filter" /></p> } </p>
运行应用程序,导航至/Movies/SearchIndex,试着按类别和名字搜索。
二、在Movie模型中添加一个新字段Rating
1.当模型改变时,创建Code First数据迁移
(1)删除Movie数据库
删除服务器连接中的MovieDBContext连接。
删除App_Data文件夹下的数据库文件Movies.mdf。
生成解决方案,确保程序没有问题。
点击“工具"菜单,点击“库程序包管理器 | 程序包管理器控制台“。
在程序包管理器控制台窗口中,输入"Enable-Migrations -ContextTypeName MvcMovie.Models.MovieDBContext”。
Enable-Migrations命令,新建了一个Migrations文件夹,里面有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 } ); }
每次迁移后,Code First调用Seed()方法,更新数据库数据,如果不存在则创建。
此时生成解决方案,否则会出错。
接下来,创建一个DbMigration类来初始化数据迁移。在此,迁移将创建一个新的数据库,所以之前需要先删除movie.mdf文件。
在程序包管理控制台窗口中,输入命令“add-migration Initial”,创建初始迁移。“Initial”名字是任意的,它命名了这次迁移的名字。
Code First迁移在Migrations文件夹中创建了一个类文件({DateStamp}_Initial.cs),这个类包含了创建数据库的模式代码。然后Seed()方法会运行,使数据库中得到测试数据。
输入命令"update-database”,创建数据库,运行Seed()方法。
如果你遇到错误提示说数据表已经存在,不能创建,可能是因为你在删除数据库后又运行过程序。这样的话,再次删除Movies.mdf文件,重新运行命令”update-database”。如果仍旧遇到问题,删除Migrations文件夹,删除数据库文件和服务器链接。
运行程序,并导航至/Movies网址。
2.在Movie模型类中添加Rating属性
打开ModelsMovie.cs文件,添加属性代码如下。
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; } }
生成解决方案。更新ViewsMoviesIndex.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>
接下来,打开ViewsMoviesCreate.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>
运行程序,导航至/Movies网址,遇到错误如下。
这个错误是因为Movie模型类改变过了,和现有数据库不一致,可以通过以下方案解决:
(1)删除数据库文件和服务器数据连接。这样做虽然简单,但是会丢失所有的数据。
(2)手动修改现有数据库,已达到与模型类文件一致。这样已有的数据库数据得到保存。
(3)使用Code First数据迁移更新数据库模式。
我们将使用第三种方法。打开MigrationsConfiguration.cs文件,添加Rating字段到每个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
”。命令执行后,VS会打开AddRatingMig文件,在Up()方法中,创建了rate列。
生成解决方案,输入命令“update-database”。
重新运行应用程序,导航至/Movies网址,查看Rate字段。