读书人

MVC中使用EF(六):更新关联数据

发布时间: 2013-10-09 22:26:11 作者: rapoo

MVC中使用EF(6):更新关联数据

更新关联数据By Tom Dykstra|July 30, 2013Translated by litdwg原文地址:http://www.asp.net/mvc/tutorials/getting-started-with-ef-using-mvc/updating-related-data-with-the-entity-framework-in-an-asp-net-mvc-application

Contoso University示例网站演示如何使用Entity Framework 5创建ASP.NET MVC 4应用程序。Entity Framework有三种处理数据的方式: Database First, Model First, and Code First. 本指南使用代码优先。其它方式请查询资料。示例程序是为Contoso University建立一个网站。功能包括:学生管理、课程创建、教师分配。 本系列指南逐步讲述如何实现这一网站程序。

如有问题,可在这些讨论区提问: ASP.NET Entity Framework forum, the Entity Framework and LINQ to Entities forum, or StackOverflow.com.

上一节完成了相关联数据的显示,本节将学习如何更新关联数据。大部分关联关系可通过更新相应的外键来完成。对于多对多关系,EF没有直接暴漏连接表,需要显式的操作导航属性(向其中添加、移除实体)来完成。

将要完成的效果如下:

MVC中使用EF(六):更新关联数据

MVC中使用EF(六):更新关联数据

定制课程的 Create 和Edit 页面

课程实体创建后是和某个部门有关联的。为了展示这一点,自动生成的代码生成了相应的控制器方法以及创建、编辑视图,其中包括可选择部门的下拉列表。下拉列表设置 Course.DepartmentID外键属性,这样EF就可以正确加载Department 导航属性的对应实体。这里只简单修改代码,增加错误处理和下拉列表排序功能。

CourseController.cs, Edit 和 Create 方法修改后代码如下:

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 (DataException /* dex */)   {      //Log the error (uncomment dex variable name after DataException and add a line here to write a log.)      ModelState.AddModelError("", "Unable to save changes. Try again, and if the problem persists, see your system administrator.");   }   PopulateDepartmentsDropDownList(course.DepartmentID);   return View(course);}public ActionResult Edit(int id){   Course course = db.Courses.Find(id);   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 (DataException /* dex */)   {      //Log the error (uncomment dex variable name after DataException and add a line here to write a log.)      ModelState.AddModelError("", "Unable to save changes. Try again, and if the problem persists, see your system administrator.");   }   PopulateDepartmentsDropDownList(course.DepartmentID);   return View(course);}private void PopulateDepartmentsDropDownList(object selectedDepartment = null){   var departmentsQuery = from d in db.Departments                          orderby d.Name                          select d;   ViewBag.DepartmentID = new SelectList(departmentsQuery, "DepartmentID", "Name", selectedDepartment);} 

PopulateDepartmentsDropDownList 方法获取按名排列的部门列表,为下拉列表构建一个SelectList 集合,使用 ViewBag 属性将其传递到视图.方法有一个可选参数selectedDepartment 以便设置下拉列表默认值.视图将把DepartmentID 传递给DropDownList 帮助器,帮助器从 ViewBag 中寻找名为DepartmentID的 SelectList.

HttpGet Create 调用 PopulateDepartmentsDropDownList 方法时不使用默认值,因为此时还没有创建新课程数据:

public ActionResult Create(){    PopulateDepartmentsDropDownList();    return View();}

HttpGet Edit 方法则设置默认值,因为此时课程在编辑时有原始的部门信息:

public ActionResult Edit(int id){    Course course = db.Courses.Find(id);    PopulateDepartmentsDropDownList(course.DepartmentID);    return View(course);}

HttpPost 方法在捕获异常之后再次显示创建或编辑页面时,初始化下拉列表默认值:

   catch (DataException /* dex */)   {      //Log the error (uncomment dex variable name after DataException and add a line here to write a log.)      ModelState.AddModelError("", "Unable to save changes. Try again, and if the problem persists, see your system administrator.");   }   PopulateDepartmentsDropDownList(course.DepartmentID);   return View(course);

代码确保如果发生异常返回页面时,原有的操作数据还在.

Views\Course\Create.cshtml,在 Title 域之前添加代码,提供录入课程编号的编辑域。之前曾经介绍过,自动生成代码不会保护对主键的编辑域.

@model ContosoUniversity.Models.Course@{    ViewBag.Title = "Create";}<h2>Create</h2>@using (Html.BeginForm()){    @Html.AntiForgeryToken()    @Html.ValidationSummary(true)    <fieldset>        <legend>Course</legend>        <div class="editor-label">            @Html.LabelFor(model => model.CourseID)        </div>        <div class="editor-field">            @Html.EditorFor(model => model.CourseID)            @Html.ValidationMessageFor(model => model.CourseID)        </div>        <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.Credits)        </div>        <div class="editor-field">            @Html.EditorFor(model => model.Credits)            @Html.ValidationMessageFor(model => model.Credits)        </div>        <div class="editor-label">            @Html.LabelFor(model => model.DepartmentID, "Department")        </div>        <div class="editor-field">            @Html.DropDownList("DepartmentID", String.Empty)            @Html.ValidationMessageFor(model => model.DepartmentID)        </div>        <p>            <input type="submit" value="Create" />        </p>    </fieldset>}<div>    @Html.ActionLink("Back to List", "Index")</div>@section Scripts {    @Scripts.Render("~/bundles/jqueryval")}

Views\Course\Edit.cshtml, Views\Course\Delete.cshtml,和Views\Course\Details.cshtml,添加如下代码

<div class="editor-label">    @Html.LabelFor(model => model.CourseID)</div><div class="editor-field">    @Html.DisplayFor(model => model.CourseID)</div>

运行 Create 页面:

MVC中使用EF(六):更新关联数据

点击Create. Index页面将显示新创建的课程信息。列表中的部门名称来自于导航属性,说明正确建立了关联。

MVC中使用EF(六):更新关联数据

运行 Edit 页面.

MVC中使用EF(六):更新关联数据

修改数据,点击 Save.索引页面显示更新后的数据.

为 Instructors添加编辑页面

编辑instructor 记录时希望同时更新所在办公室信息. Instructor 和 OfficeAssignment 实体存在一对零或一的关系,也就是要处理以下场景:

读书人网 >VC/MFC

热点推荐