这是微软官方教程Getting Started with Entity Framework 6 Code First using MVC 5 系列的翻译,这里是第八篇:为ASP.NET MVC应用程序更新相关数据
原文:
译文版权所有,谢绝全文转载——但您可以在您的网站上添加到该教程的链接。
在之前的教程中您已经成功显示了相关数据。在本教程中你将学习如何对相关数据进行更新。对于大多数关系,可以从主键或者导航属性来进行更新。对于多对多关系,实体框架不会直接公开连接表,所以你可以从相应的导航属性添加和移除实体。
下面的截图显示了你将要实现的页面。
为课程自定义创建和编辑页
当创建新的课程实体时,他必须拥有一个和已存在系的关系。为此,脚手架代码创建的控制器方法及新建和编辑视图种豆包含了用于选择系的下拉列表。下拉列表用来设置Course.DepartmentID外键属性,这对于实体框架通过Department导航属性来加载Department实体是必须的。你将使用脚手架代码,但需要对其做一些小的改动来增加错误处理和对列表内容进行排序。
在Coursecontroller.cs中,删除之前的Create和Edit方法,并添加下面的代码:
private void PopulateDepartmentsDropDownList(object selectedDrpaerment = null) { var departmentsQuery = from d in db.Departments orderby d.Name select d; ViewBag.DepartmentID = new SelectList(departmentsQuery, "DepartmentID", "Name", selectedDrpaerment); } public ActionResult Create() { PopulateDepartmentsDropDownList(); return View(); } [HttpPost] [ValidateAntiForgeryToken] public ActionResult Create([Bind(Include = "CourseID,Title,Credits,DepartmentID")]Course course) { try { if (ModelState.IsValid) { db.Courses.Add(course); db.SaveChanges(); return RedirectToAction("Index"); } } catch (RetryLimitExceededException) { ModelState.AddModelError("", "无法保存数据,请重试或联系管理员。"); } PopulateDepartmentsDropDownList(course.DepartmentID); return View(course); } public ActionResult Edit(int? id) { if (id == null) { return new HttpStatusCodeResult(HttpStatusCode.BadRequest); } Course course = db.Courses.Find(id); if (course == null) { return HttpNotFound(); } PopulateDepartmentsDropDownList(course.DepartmentID); return View(course); } [HttpPost,ValidateAntiForgeryToken] public ActionResult Edit([Bind(Include="CourseID,Title,Credits,DepartmentID")]Course course) { try { if (ModelState.IsValid) { db.Entry(course).State = EntityState.Modified; db.SaveChanges(); return RedirectToAction("Index"); } } catch (RetryLimitExceededException) { ModelState.AddModelError("", "无法保存更改,请重试或联系管理员。"); } PopulateDepartmentsDropDownList(course.DepartmentID); return View(course); }
在文件的开头增加以下引用:
using System.Data.Entity.Infrastructure;
PopulateDepartmentsDropDownList方法获取所有的系列表并按照名称进行排序来创建一个下拉列表。并通过ViewBag属性传递到视图上。该方法接收一个可选参数selectedDepartment,在下拉列表渲染时允许调用代码指定被选择的项目。视图将传递DepartmentID名称给下拉列表帮助器,然后帮助器知道应当使用DepartmentID名来在ViewBag中对象进行下拉列表的查找。
HttpGet Create方法调用PopulateDepartmentsDropDownList方法,但并不设置已选项目,因为对于一个新的课程来说,尚未确定其所属的系。
public ActionResult Create() { PopulateDepartmentsDropDownList(); return View(); }
HttpGetEdit方法设置所选的项目,基于已经分配给正在编辑的课程的系ID:
public ActionResult Edit(int? id) { if (id == null) { return new HttpStatusCodeResult(HttpStatusCode.BadRequest); } Course course = db.Courses.Find(id); if (course == null) { return HttpNotFound(); } PopulateDepartmentsDropDownList(course.DepartmentID); return View(course); }
Create和Edit的HttpPost方法还包括当出现了错误后,重新显示页面时要再设置一次所选项目的代码:
catch (RetryLimitExceededException) { ModelState.AddModelError("", "无法保存更改,请重试或联系管理员。"); } PopulateDepartmentsDropDownList(course.DepartmentID); return View(course);
这段代码确保当页面重新显示错误信息时,已经被选择的系保持被选择状态。
Course视图已经基于系字段来使用脚手架构建了一个下拉列表。但你并不想使用系ID来作为标题,所以在Views\Course\Create.cshtml中进行以下高亮部分的更改:
@model ContosoUniversity.Models.Course @{ ViewBag.Title = "Create"; } <h2>Create</h2> @using (Html.BeginForm()) { @Html.AntiForgeryToken() <div class="form-horizontal"> <h4>Course</h4> <hr /> @Html.ValidationSummary(true) <div class="form-group"> @Html.LabelFor(model => model.CourseID, new { @class = "control-label col-md-2" }) <div class="col-md-10"> @Html.EditorFor(model => model.CourseID) @Html.ValidationMessageFor(model => model.CourseID) </div> </div> <div class="form-group"> @Html.LabelFor(model => model.Title, new { @class = "control-label col-md-2" }) <div class="col-md-10"> @Html.EditorFor(model => model.Title) @Html.ValidationMessageFor(model => model.Title) </div> </div> <div class="form-group"> @Html.LabelFor(model => model.Credits, new { @class = "control-label col-md-2" }) <div class="col-md-10"> @Html.EditorFor(model => model.Credits) @Html.ValidationMessageFor(model => model.Credits) </div> </div> <div class="form-group"> <label class="control-label col-md-2" for="DepartmentID">Department</label> <div class="col-md-10"> @Html.DropDownList("DepartmentID", String.Empty) @Html.ValidationMessageFor(model => model.DepartmentID) </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") }
之后在Edit视图中进行相同的更改。
通常脚手架不会使用主键来生成字段,因为主键值是由数据库生成的,无法更改且对用户显示也没有意义。对于课程实体脚手架代码包含了一个用于CourseID的文本框,因为DatabaseGeneratedOption.None特性意味着用户应当可以输入主键值。但它并不明白因为该号码只有在你想要让其显示在某些特定视图中才是有意义的。所以您需要手动添加它。
在Edit视图中,在标题字段之前添加课程编号字段。
<div class="form-group"> @Html.LabelFor(model => model.CourseID, new { @class = "Control-label col-md-2" }) <div class="col-md-10"> @Html.DisplayFor(model => model.CourseID) </div> </div>
Edit视图中已经有一个课程编号的隐藏字段(Html.HiddenFor帮助器)。为隐藏字段添加一个Html.LabelFor帮助器是没必要的。因为它不会导致当用户点击保存时将课程编号包含在要发送的数据中。
在Delete和Details视图中,更改系名称的标题从"Name"到"Department"并在标题字段之前添加一个课程编号字段。
<dt> Department </dt> <dd> @Html.DisplayFor(model => model.Department.Name) </dd> <dt> @Html.DisplayNameFor(model => model.CourseID) </dt> <dd> @Html.DisplayFor(model => model.CourseID) </dd> <dt> @Html.DisplayNameFor(model => model.Title) </dt>
勘误注意:
之前的Layout页面因为疏忽路由参数写错了,请使用下面的代码替换布局页面。
View Code<!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>@ViewBag.Title - Contoso 大学</title> @Styles.Render("~/Content/css") @Scripts.Render("~/bundles/modernizr") </head> <body> <div class="navbar navbar-inverse navbar-fixed-top"> <div class="container"> <div class="navbar-header"> <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse"> <span class="icon-bar"></span> <span class="icon-bar"></span> <span class="icon-bar"></span> </button> @Html.ActionLink("Contoso 大学", "Index", "Home", null, new { @class = "navbar-brand" }) </div> <div class="navbar-collapse collapse"> <ul class="nav navbar-nav"> <li>@Html.ActionLink("主页", "Index", "Home")</li> <li>@Html.ActionLink("关于", "About", "Home")</li> <li>@Html.ActionLink("学生", "Index", "Student")</li> <li>@Html.ActionLink("教师", "Index", "Instructor")</li> <li>@Html.ActionLink("课程", "Index", "Course")</li> <li>@Html.ActionLink("系", "Index", "Department")</li> </ul> </div> </div> </div> <div class="container body-content"> @RenderBody() <hr /> <footer> <p>© @DateTime.Now.Year - Contoso 大学</p> </footer> </div> @Scripts.Render("~/bundles/jquery") @Scripts.Render("~/bundles/bootstrap") @RenderSection("scripts", required: false) </body> </html>