演练2-4:CodeFirst实例之“电影网站制作”
原文出处:http://www.asp.net/mvc/tutorials/mvc-4/getting-started-with-aspnet-mvc4/adding-a-model
EntityFramework(简称EF),支持Code First开发方法。三种开发方法数据库优先(Database First)、模型优先(Model First)、代码优先(Code First)。Code First,首先创建模型对象的类,然后相应的数据库就可以通过ORM工具自动生成,这是一种非常迅速和干净的开发流程。
我们将构建一个电影网站,如下图。
一、添加模型
1.新建一个默认的ASP.NET MVC 4 网站,名称为MvcMovie。
2.右击Models文件夹,添加类Movie.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; } }
我们将用Movie类代表数据库中的movies信息,Movie类中的每一个属性对应数据库表中的一个字段,Movie对象的实例将会对应数据库表的一行。
3.在Models文件夹中添加MovieDBContext类
public class MovieDBContext : DbContext
{
public DbSet<Movie> Movies { get; set; }
}
MovieDBContext类代表EF movie数据库上下文,它处理在数据库中读写更新Movie类实例。DbContext类由EF提供,需要引用语句
using System.Data.Entity;
4.创建数据库连接
打开应用程序根目录下的Web.config文件,不是视图文件夹中的那个哟。在<connectionStrings>元素中,添加连接字符串。
<add name="MovieDBContext"
connectionString="Data Source=(LocalDB)\v11.0;AttachDbFilename=|DataDirectory|\Movies.mdf;Integrated Security=True"
providerName="System.Data.SqlClient"
/>
二、添加控制器
1.右击Controllers文件夹,创建Movies控制器。
如果选项没有出现,请先编译应用程序。
VS创建了MoviesController.cs、Views文件夹下面的Movies文件夹(包含Create.cshtml、Delete.cshtml、Details.cshtml、Edit.cshtml、Index.cshtml)。
ASP.NET MVC 4 自动生成了CRUD(create、read、update、delete)方法和视图,这些代码称作脚手架代码(scaffolding),现在可以进行CRUD的操作了。
2.运行程序
试着操作Edit、Details和Delete功能。
3.了解自动生成的代码
public class MoviesController : Controller { private MovieDBContext db = new MovieDBContext(); // // GET: /Movies/ public ActionResult Index() { return View(db.Movies.ToList()); }
你可以使用movie database context来查询、编辑、删除电影。db.Movies.ToList()获取Movies数据表中的所有记录,return View(db.Movies.ToList()),将结果返回给Index视图。
4.强类型模型和@model关键字
我们在之前的学习中,已经使用过将数据通过ViewBag传递给视图。ViewBag是一个动态对象,它提供了方便的后期绑定(late-bound)方法,将信息传递到视图。
ASP.NET MVC提供了传递强类型数据或对象到视图的方法。这个强类型方法允许编译时,检查代码和更好的Visual studio智能感知编辑工具。在我们的例子中,脚手架样例代码使用这种方法,创建Movies控制器和视图。
例如在Movies控制器中的Details代码如上图,如果Movie找到,Movie的实例就被传递到Details视图。 通过在视图顶部的@model语句,可以知道该视图需要的数据对象。
@model MvcMovie.Models.Movie
相同的还有Index()动作和视图。
@model IEnumerable<MvcMovie.Models.Movie>
5.理解Edit方法和视图
Edit超链接是由Html.ActionLink方法生成的,在Views\Movies\Index.cshtml视图中。
@Html.ActionLink("Edit", "Edit", new { id=item.ID })
Html.ActionLink方法可以动态产生指向某个控制器动作的HTML超链接。其中第一个参数是超链接文本(比如,<a>Edit Me</a>),第二个参数是动作名字,最后一个是匿名对象,用来生成路由数据(比如,Id为4)。上图的超链接是http://localhost:xxxx/Movies/Edit/4。
默认的路由创建在App_Start\RouteConfig.cs文件中,使用{controller}/{action}/{id}模式。
public static void RegisterRoutes(RouteCollection routes) { routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); routes.MapRoute( name: "Default", url: "{controller}/{action}/{id}", defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional } ); }
你也可以自己在浏览器的地址栏里面输入查询字符串,比如http://localhost:xxxx/Movies/Edit?ID=4。
打开Movies控制器,可以看到有两个Edit动作。 尝试分析下代码。
// // GET: /Movies/Edit/5 public ActionResult Edit(int id = 0) { Movie movie = db.Movies.Find(id); if (movie == null) { return HttpNotFound(); } return View(movie); } // // POST: /Movies/Edit/5 [HttpPost] public ActionResult Edit(Movie movie) { if (ModelState.IsValid) { db.Entry(movie).State = EntityState.Modified; db.SaveChanges(); return RedirectToAction("Index"); } return View(movie); }
Edit视图代码如下。
@model MvcMovie.Models.Movie @{ ViewBag.Title = "Edit"; } <h2>Edit</h2> @using (Html.BeginForm()) { @Html.ValidationSummary(true) <fieldset> <legend>Movie</legend> @Html.HiddenFor(model => model.ID) <div class="editor-label"> @Html.LabelFor(model => model.Title) </div> <div class="editor-field"> @Html.EditorFor(model => model.Title) @Html.ValidationMessageFor(model => model.Title) </div> <div class="editor-label"> @Html.LabelFor(model => model.ReleaseDate) </div> <div class="editor-field"> @Html.EditorFor(model => model.ReleaseDate) @Html.ValidationMessageFor(model => model.ReleaseDate) </div> <div class="editor-label"> @Html.LabelFor(model => model.Genre) </div> <div class="editor-field"> @Html.EditorFor(model => model.Genre) @Html.ValidationMessageFor(model => model.Genre) </div> <div class="editor-label"> @Html.LabelFor(model => model.Price) </div> <div class="editor-field"> @Html.EditorFor(model => model.Price) @Html.ValidationMessageFor(model => model.Price) </div> <p> <input type="submit" value="Save" /> </p> </fieldset> } <div> @Html.ActionLink("Back to List", "Index") </div> @section Scripts { @Scripts.Render("~/bundles/jqueryval") }
运行程序,打开/Movies网址,点击Edit,跳转至Edit视图,查看HTML代码如下。
<form action="/Movies/Edit/4" method="post"> <fieldset> <legend>Movie</legend> <input data-val="true" data-val-number="The field ID must be a number." data-val-required="The ID field is required." id="ID" name="ID" type="hidden" value="4" /> <div class="editor-label"> <label for="Title">Title</label> </div> <div class="editor-field"> <input class="text-box single-line" id="Title" name="Title" type="text" value="Rio Bravo" /> <span class="field-validation-valid" data-valmsg-for="Title" data-valmsg-replace="true"></span> </div> <div class="editor-label"> <label for="ReleaseDate">ReleaseDate</label> </div> <div class="editor-field"> <input class="text-box single-line" data-val="true" data-val-date="The field ReleaseDate must be a date." data-val-required="The ReleaseDate field is required." id="ReleaseDate" name="ReleaseDate" type="text" value="4/15/1959 12:00:00 AM" /> <span class="field-validation-valid" data-valmsg-for="ReleaseDate" data-valmsg-replace="true"></span> </div> <div class="editor-label"> <label for="Genre">Genre</label> </div> <div class="editor-field"> <input class="text-box single-line" id="Genre" name="Genre" type="text" value="Western" /> <span class="field-validation-valid" data-valmsg-for="Genre" data-valmsg-replace="true"></span> </div> <div class="editor-label"> <label for="Price">Price</label> </div> <div class="editor-field"> <input class="text-box single-line" data-val="true" data-val-number="The field Price must be a number." data-val-required="The Price field is required." id="Price" name="Price" type="text" value="2.99" /> <span class="field-validation-valid" data-valmsg-for="Price" data-valmsg-replace="true"></span> </div> <p> <input type="submit" value="Save" /> </p> </fieldset> </form>
5.学习Details和Delete动作代码
打开Movies控制器,查看Details动作代码。
public ActionResult Details(int? id) { if (id == null) { return new HttpStatusCodeResult(HttpStatusCode.BadRequest); } Movie movie = db.Movies.Find(id); if (movie == null) { return HttpNotFound(); } return View(movie); }
查看Delete和DeleteConfirmed动作。
// GET: /Movies/Delete/5 public ActionResult Delete(int? id) { if (id == null) { return new HttpStatusCodeResult(HttpStatusCode.BadRequest); } Movie movie = db.Movies.Find(id); if (movie == null) { return HttpNotFound(); } return View(movie); } // POST: /Movies/Delete/5 [HttpPost, ActionName("Delete")] [ValidateAntiForgeryToken] public ActionResult DeleteConfirmed(int id) { Movie movie = db.Movies.Find(id); db.Movies.Remove(movie); db.SaveChanges(); return RedirectToAction("Index"); }
这里HttpGet Delete动作并不是要删除某个电影,它返回了一个视图,可以提交HttpPost删除请求。直接执行HttpPost请求容易导致安全漏洞。
因为HttpPost Delete函数签名和HttpGet一样,所以使用了如下的处理。
// GET: /Movies/Delete/5 public ActionResult Delete(int? id) // // POST: /Movies/Delete/5 [HttpPost, ActionName("Delete")] public ActionResult DeleteConfirmed(int id)