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没有直接暴漏连接表,需要显式的操作导航属性(向其中添加、移除实体)来完成。

一、定制课程的Create和Edit页面

将要完成的效果如下:

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

  1. public ActionResult Create()
  2. {
  3. PopulateDepartmentsDropDownList();
  4. return View();
  5. }
  6.  
  7. [HttpPost]
  8. [ValidateAntiForgeryToken]
  9. public ActionResult Create(
  10. [Bind(Include = "CourseID,Title,Credits,DepartmentID")]
  11. Course course)
  12. {
  13. try
  14. {
  15. if (ModelState.IsValid)
  16. {
  17. db.Courses.Add(course);
  18. db.SaveChanges();
  19. return RedirectToAction("Index");
  20. }
  21. }
  22. catch (DataException /* dex */)
  23. {
  24. //Log the error (uncomment dex variable name after DataException and add a line here to write a log.)
  25. ModelState.AddModelError("", "Unable to save changes. Try again, and if the problem persists, see your system administrator.");
  26. }
  27. PopulateDepartmentsDropDownList(course.DepartmentID);
  28. return View(course);
  29. }
  30.  
  31. public ActionResult Edit(int id)
  32. {
  33. Course course = db.Courses.Find(id);
  34. PopulateDepartmentsDropDownList(course.DepartmentID);
  35. return View(course);
  36. }
  37.  
  38. [HttpPost]
  39. [ValidateAntiForgeryToken]
  40. public ActionResult Edit(
  41. [Bind(Include = "CourseID,Title,Credits,DepartmentID")]
  42. Course course)
  43. {
  44. try
  45. {
  46. if (ModelState.IsValid)
  47. {
  48. db.Entry(course).State = EntityState.Modified;
  49. db.SaveChanges();
  50. return RedirectToAction("Index");
  51. }
  52. }
  53. catch (DataException /* dex */)
  54. {
  55. //Log the error (uncomment dex variable name after DataException and add a line here to write a log.)
  56. ModelState.AddModelError("", "Unable to save changes. Try again, and if the problem persists, see your system administrator.");
  57. }
  58. PopulateDepartmentsDropDownList(course.DepartmentID);
  59. return View(course);
  60. }
  61.  
  62. private void PopulateDepartmentsDropDownList(object selectedDepartment = null)
  63. {
  64. var departmentsQuery = from d in db.Departments
  65. orderby d.Name
  66. select d;
  67. ViewBag.DepartmentID = new SelectList(departmentsQuery, "DepartmentID", "Name", selectedDepartment);
  68. }

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

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

  1. public ActionResult Create()
  2. {
  3. PopulateDepartmentsDropDownList();
  4. return View();
  5. }

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

  1. public ActionResult Edit(int id)
  2. {
  3. Course course = db.Courses.Find(id);
  4. PopulateDepartmentsDropDownList(course.DepartmentID);
  5. return View(course);
  6. }

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

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

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

2.修改Create视图

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

  1. model ContosoUniversity.Models.Course
  2.  
  3. @{
  4. ViewBag.Title = "Create";
  5. }
  6.  
  7. <h2>Create</h2>
  8.  
  9. @using (Html.BeginForm())
  10. {
  11. @Html.AntiForgeryToken()
  12. @Html.ValidationSummary(true)
  13.  
  14. <fieldset>
  15. <legend>Course</legend>
  16.  
  17. <div class="editor-label">
  18. @Html.LabelFor(model => model.CourseID)
  19. </div>
  20. <div class="editor-field">
  21. @Html.EditorFor(model => model.CourseID)
  22. @Html.ValidationMessageFor(model => model.CourseID)
  23. </div>
  24.  
  25. <div class="editor-label">
  26. @Html.LabelFor(model => model.Title)
  27. </div>
  28. <div class="editor-field">
  29. @Html.EditorFor(model => model.Title)
  30. @Html.ValidationMessageFor(model => model.Title)
  31. </div>
  32.  
  33. <div class="editor-label">
  34. @Html.LabelFor(model => model.Credits)
  35. </div>
  36. <div class="editor-field">
  37. @Html.EditorFor(model => model.Credits)
  38. @Html.ValidationMessageFor(model => model.Credits)
  39. </div>
  40.  
  41. <div class="editor-label">
  42. @Html.LabelFor(model => model.DepartmentID, "Department")
  43. </div>
  44. <div class="editor-field">
  45. @Html.DropDownList("DepartmentID", String.Empty)
  46. @Html.ValidationMessageFor(model => model.DepartmentID)
  47. </div>
  48.  
  49. <p>
  50. <input type="submit" value="Create" />
  51. </p>
  52. </fieldset>
  53. }
  54.  
  55. <div>
  56. @Html.ActionLink("Back to List", "Index")
  57. </div>
  58.  
  59. @section Scripts {
  60. @Scripts.Render("~/bundles/jqueryval")
  61. }

同样地修改Views\Course\Edit、Delete和Details视图,在Title字段前添加course number字段。

  1. <div class="display-label">
  2. @Html.DisplayNameFor(model => model.CourseID)
  3. </div>
  4. <div class="display-field">
  5. @Html.DisplayFor(model => model.CourseID)
  6. </div>

运行Create、Edit、Delete、Details,查看效果。

二、为教师创建Edit页面

当你编辑一条教师记录时,你可能希望能够更新教师的办公地点。Instructor实体和OfficeAssignment之间是一对一的关系,所以必须处理以下情况:

  • 如果用户清除了办公地点,而它本来是有值的,那么你必须删除OfficeAssignment实体。
  • 如果用户输入办公地点值,而它本来是空的,那么你必须新建一个OfficeAssignment实体。
  • 如果用户改变了办公地点的值,那么你必须改变已有的OfficeAssignment实体值。

1.添加办公地点

Instructor控制器中,自动生成的HttpGet Edit方法代码如下:

  1. public ActionResult Edit(int id = )
  2. {
  3. Instructor instructor = db.Instructors.Find(id);
  4. if (instructor == null)
  5. {
  6. return HttpNotFound();
  7. }
  8. ViewBag.InstructorID = new SelectList(db.OfficeAssignments, "InstructorID", "Location", instructor.InstructorID);
  9. return View(instructor);
  10. }

自动生成的代码创建了下拉列表,我们将其修改以下,使用文本框:

  1. public ActionResult Edit(int id)
  2. {
  3. Instructor instructor = db.Instructors
  4. .Include(i => i.OfficeAssignment)
  5. .Where(i => i.InstructorID == id)
  6. .Single();
  7. return View(instructor);
  8. }

使用eager loading贪婪加载方式获取OfficeAssignment实体,就不能使用Find方法,所以我们使用了Where。

将HttpPost Edit方法替换为如下代码。

  1. [HttpPost]
  2. [ValidateAntiForgeryToken]
  3. public ActionResult Edit(int id, FormCollection formCollection)
  4. {
  5. var instructorToUpdate = db.Instructors
  6. .Include(i => i.OfficeAssignment)
  7. .Where(i => i.InstructorID == id)
  8. .Single();
  9.  
  10. if (TryUpdateModel(instructorToUpdate, "",
  11. new string[] { "LastName", "FirstMidName", "HireDate", "OfficeAssignment" }))
  12. {
  13. try
  14. {
  15. if (String.IsNullOrWhiteSpace(instructorToUpdate.OfficeAssignment.Location))
  16. {
  17. instructorToUpdate.OfficeAssignment = null;
  18. }
  19.  
  20. db.Entry(instructorToUpdate).State = EntityState.Modified;
  21. db.SaveChanges();
  22.  
  23. return RedirectToAction("Index");
  24. }
  25. catch (DataException /* dex */)
  26. {
  27. //Log the error (uncomment dex variable name after DataException and add a line here to write a log.
  28. ModelState.AddModelError("", "Unable to save changes. Try again, and if the problem persists, see your system administrator.");
  29. }
  30. }
  31. ViewBag.InstructorID = new SelectList(db.OfficeAssignments, "InstructorID", "Location", id);
  32. return View(instructorToUpdate);
  33. }

这部分代码的作用是:

  • 从数据库通过贪婪加载获取Instructor和OfficeAssignment实体。这是和自动生成的HttpGet Edit方法一样的。

  • 使用模型绑定器数据更新Instructor实体。

  1. if (TryUpdateModel(instructorToUpdate, "",
  2. new string[] { "LastName", "FirstMidName", "HireDate", "OfficeAssignment" }))
  • 如果办公室信息为空,将Instructor.OfficeAssignment属性设为null,OfficeAssignment表中相应的记录也将删除。
  1. if (String.IsNullOrWhiteSpace(instructorToUpdate.OfficeAssignment.Location))
  2. {
  3. instructorToUpdate.OfficeAssignment = null;
  4. }
  • 保存对数据库的修改。

Views\Instructor\Edit.cshtmlHire Date 的div标记之后, 添加办公室信息的编辑域:

  1. <div class="editor-label">
  2. @Html.LabelFor(model => model.OfficeAssignment.Location)
  3. </div>
  4. <div class="editor-field">
  5. @Html.EditorFor(model => model.OfficeAssignment.Location)
  6. @Html.ValidationMessageFor(model => model.OfficeAssignment.Location)
  7. </div>

运行,测试效果。

2.添加教师讲授的课程数据更新

      在教师Edit页面,增加对教师承担课程编辑的功能,效果如下。

Course和Instructor实体之间是多对过关系,我们并没有手动生成它们之间的连接表,自动生成的连接表无法直接访问。事实上,我们将通过在Instructor.Courses导航属性中,添加或删除关联实体的方式来实现关系的维护。

改变老师承担课程的功能,是通过一组复选框来实现。列出数据库中所有课程,教师承担某课程,则该复选框选中。用户通过选中或者取消选中的操作修改课程的分配情况。如果课程数目很多,你可能希望使用别的显示方法,但操作导航属性来添加或删除关系的方法是一样的。

为了能够显示这一组复选框,我们将使用视图模型类。在Models文件夹中,创建AssignedCourseData.cs文件。

  1. namespace ContosoUniversity.ViewModels
  2. {
  3. public class AssignedCourseData
  4. {
  5. public int CourseID { get; set; }
  6. public string Title { get; set; }
  7. public bool Assigned { get; set; }
  8. }
  9. }

更新Instructor控制器的Edit方法。

  1. public ActionResult Edit(int id)
  2. {
  3. Instructor instructor = db.Instructors
  4. .Include(i => i.OfficeAssignment)
  5. .Include(i => i.Courses)
  6. .Where(i => i.InstructorID == id)
  7. .Single();
  8. PopulateAssignedCourseData(instructor);
  9. return View(instructor);
  10. }
  11.  
  12. private void PopulateAssignedCourseData(Instructor instructor)
  13. {
  14. var allCourses = db.Courses;
  15. var instructorCourses = new HashSet<int>(instructor.Courses.Select(c => c.CourseID));
  16. var viewModel = new List<AssignedCourseData>();
  17. foreach (var course in allCourses)
  18. {
  19. viewModel.Add(new AssignedCourseData
  20. {
  21. CourseID = course.CourseID,
  22. Title = course.Title,
  23. Assigned = instructorCourses.Contains(course.CourseID)
  24. });
  25. }
  26. ViewBag.Courses = viewModel;
  27. }

代码使用贪婪模式加载Courses导航属性,调用PopulateAssignedCourseData方法实现为视图提供AssignedCourseData视图模型的数据。

PopulateAssignedCourseData方法读取所有Course实体。对每一个Courses检查是否已经存在于某教师的导航属性中。为了提高效率,将当前承担课程的ID形成一个HashSet集合。教师承担某课程,则Assigned属性将设为 true。视图将使用此属性决定哪些选择框处于被选中状态。最后通过ViewBag的一个属性将列表传递到视图。

下一步,完成保存代码。使用如下代码替换HttpPost Edit方法的代码,调用一个新的方法更新Instructor实体的Courses导航属性。

  1. [HttpPost]
  2. [ValidateAntiForgeryToken]
  3. public ActionResult Edit(int id, FormCollection formCollection, string[] selectedCourses)
  4. {
  5. var instructorToUpdate = db.Instructors
  6. .Include(i => i.OfficeAssignment)
  7. .Include(i => i.Courses)
  8. .Where(i => i.InstructorID == id)
  9. .Single();
  10. if (TryUpdateModel(instructorToUpdate, "",
  11. new string[] { "LastName", "FirstMidName", "HireDate", "OfficeAssignment" }))
  12. {
  13. try
  14. {
  15. if (String.IsNullOrWhiteSpace(instructorToUpdate.OfficeAssignment.Location))
  16. {
  17. instructorToUpdate.OfficeAssignment = null;
  18. }
  19.  
  20. UpdateInstructorCourses(selectedCourses, instructorToUpdate);
  21.  
  22. db.Entry(instructorToUpdate).State = EntityState.Modified;
  23. db.SaveChanges();
  24.  
  25. return RedirectToAction("Index");
  26. }
  27. catch (DataException /* dex */)
  28. {
  29. //Log the error (uncomment dex variable name after DataException and add a line here to write a log.
  30. ModelState.AddModelError("", "Unable to save changes. Try again, and if the problem persists see your system administrator.");
  31. }
  32. }
  33. PopulateAssignedCourseData(instructorToUpdate);
  34. return View(instructorToUpdate);
  35. }
  36.  
  37. private void UpdateInstructorCourses(string[] selectedCourses, Instructor instructorToUpdate)
  38. {
  39. if (selectedCourses == null)
  40. {
  41. instructorToUpdate.Courses = new List<Course>();
  42. return;
  43. }
  44.  
  45. var selectedCoursesHS = new HashSet<string>(selectedCourses);
  46. var instructorCourses = new HashSet<int>
  47. (instructorToUpdate.Courses.Select(c => c.CourseID));
  48. foreach (var course in db.Courses)
  49. {
  50. if (selectedCoursesHS.Contains(course.CourseID.ToString()))
  51. {
  52. if (!instructorCourses.Contains(course.CourseID))
  53. {
  54. instructorToUpdate.Courses.Add(course);
  55. }
  56. }
  57. else
  58. {
  59. if (instructorCourses.Contains(course.CourseID))
  60. {
  61. instructorToUpdate.Courses.Remove(course);
  62. }
  63. }
  64. }

因为自动生成的视图中,不包含Course实体集合, 因此模型绑定器不能直接更新Courses导航属性。更新由UpdateInstructorCourses方法完成。因此要把Courses属性从模型绑定器中排除出去。这并不需要修改TryUpdateModel的代码,因为使用了白名单,Courses不在名单之内。

如果没有选中任何课程,UpdateInstructorCourses将Courses导航属性设为一个空的列表:

  1. if (selectedCourses == null)
  2. {
  3. instructorToUpdate.Courses = new List<Course>();
  4. return;
  5. }

代码执行循环检查数据库中的每一课程,若此课程被选中则判断是否已经包含在相关数据中,如果没有则添加到导航属性。为了提高效率,把选中课程 Id和已有课程ID放在哈希表中。

  1. if (selectedCoursesHS.Contains(course.CourseID.ToString()))
  2. {
  3. if (!instructorCourses.Contains(course.CourseID))
  4. {
  5. instructorToUpdate.Courses.Add(course);
  6. }
  7. }

如果某课程没有选中但存在于Instructor.Courses导航属性, 则将其从中移除。

  1. else
  2. {
  3. if (instructorCourses.Contains(course.CourseID))
  4. {
  5. instructorToUpdate.Courses.Remove(course);
  6. }
  7. }

在Views\Instructor\Edit.cshtml文件中,在OfficeAssignment之后,添加课程复选框。

  1. @model ContosoUniversity.Models.Instructor
  2.  
  3. @{
  4. ViewBag.Title = "Edit";
  5. }
  6.  
  7. <h2>Edit</h2>
  8.  
  9. @using (Html.BeginForm())
  10. {
  11. @Html.AntiForgeryToken()
  12. @Html.ValidationSummary(true)
  13.  
  14. <fieldset>
  15. <legend>Instructor</legend>
  16.  
  17. @Html.HiddenFor(model => model.InstructorID)
  18.  
  19. <div class="editor-label">
  20. @Html.LabelFor(model => model.LastName)
  21. </div>
  22. <div class="editor-field">
  23. @Html.EditorFor(model => model.LastName)
  24. @Html.ValidationMessageFor(model => model.LastName)
  25. </div>
  26.  
  27. <div class="editor-label">
  28. @Html.LabelFor(model => model.FirstMidName)
  29. </div>
  30. <div class="editor-field">
  31. @Html.EditorFor(model => model.FirstMidName)
  32. @Html.ValidationMessageFor(model => model.FirstMidName)
  33. </div>
  34.  
  35. <div class="editor-label">
  36. @Html.LabelFor(model => model.HireDate)
  37. </div>
  38. <div class="editor-field">
  39. @Html.EditorFor(model => model.HireDate)
  40. @Html.ValidationMessageFor(model => model.HireDate)
  41. </div>
  42.  
  43. <div class="editor-label">
  44. @Html.LabelFor(model => model.OfficeAssignment.Location)
  45. </div>
  46. <div class="editor-field">
  47. @Html.EditorFor(model => model.OfficeAssignment.Location)
  48. @Html.ValidationMessageFor(model => model.OfficeAssignment.Location)
  49. </div>
  50.  
  51. <div class="editor-field">
  52. <table>
  53. <tr>
  54. @{
  55. int cnt = ;
  56. List<ContosoUniversity.ViewModels.AssignedCourseData> courses = ViewBag.Courses;
  57.  
  58. foreach (var course in courses) {
  59. if (cnt++ % == ) {
  60. @: </tr> <tr>
  61. }
  62. @: <td>
  63. <input type="checkbox"
  64. name="selectedCourses"
  65. value="@course.CourseID"
  66. @(Html.Raw(course.Assigned ? "checked=\"checked\"" : "")) />
  67. @course.CourseID @: @course.Title
  68. @:</td>
  69. }
  70. @: </tr>
  71. }
  72. </table>
  73. </div>
  74. <p>
  75. <input type="submit" value="Save" />
  76. </p>
  77. </fieldset>
  78. }
  79.  
  80. <div>
  81. @Html.ActionLink("Back to List", "Index")
  82. </div>
  83.  
  84. @section Scripts {
  85. @Scripts.Render("~/bundles/jqueryval")
  86. }

这段代码创建了一个包含三列的表格。每一列包含一个复选框、课程编号和名称。所有复选框的名字都是一样的 ("selectedCourses"), 模型绑定器由此得知将其作为一组信息来处理。复选框的 value设为对于课程的 CourseID。当编辑提交之后,模型绑定器将被选中的复选框的值组合为一个数组传给控制器。

更新Views\Instructor\Index.cshtml视图,在Office列之后添加Courses,更新Details视图。

  1. @model ContosoUniversity.ViewModels.InstructorIndexData
  2.  
  3. @{
  4. ViewBag.Title = "Instructors";
  5. }
  6.  
  7. <h2>Instructors</h2>
  8.  
  9. <p>
  10. @Html.ActionLink("Create New", "Create")
  11. </p>
  12. <table>
  13. <tr>
  14. <th></th>
  15. <th>Last Name</th>
  16. <th>First Name</th>
  17. <th>Hire Date</th>
  18. <th>Office</th>
  19. <th>Courses</th>
  20. </tr>
  21. @foreach (var item in Model.Instructors)
  22. {
  23. string selectedRow = "";
  24. if (item.InstructorID == ViewBag.InstructorID)
  25. {
  26. selectedRow = "selectedrow";
  27. }
  28. <tr class="@selectedRow" valign="top">
  29. <td>
  30. @Html.ActionLink("Select", "Index", new { id = item.InstructorID }) |
  31. @Html.ActionLink("Edit", "Edit", new { id = item.InstructorID }) |
  32. @Html.ActionLink("Details", "Details", new { id = item.InstructorID }) |
  33. @Html.ActionLink("Delete", "Delete", new { id = item.InstructorID })
  34. </td>
  35. <td>
  36. @item.LastName
  37. </td>
  38. <td>
  39. @item.FirstMidName
  40. </td>
  41. <td>
  42. @String.Format("{0:d}", item.HireDate)
  43. </td>
  44. <td>
  45. @if (item.OfficeAssignment != null)
  46. {
  47. @item.OfficeAssignment.Location
  48. }
  49. </td>
  50. <td>
  51. @{
  52. foreach (var course in item.Courses)
  53. {
  54. @course.CourseID @: @course.Title <br />
  55. }
  56. }
  57. </td>
  58. </tr>
  59. }
  60. </table>
  61.  
  62. @if (Model.Courses != null)
  63. {
  64. <h3>Courses Taught by Selected Instructor</h3>
  65. <table>
  66. <tr>
  67. <th></th>
  68. <th>ID</th>
  69. <th>Title</th>
  70. <th>Department</th>
  71. </tr>
  72.  
  73. @foreach (var item in Model.Courses)
  74. {
  75. string selectedRow = "";
  76. if (item.CourseID == ViewBag.CourseID)
  77. {
  78. selectedRow = "selectedrow";
  79. }
  80.  
  81. <tr class="@selectedRow">
  82.  
  83. <td>
  84. @Html.ActionLink("Select", "Index", new { courseID = item.CourseID })
  85. </td>
  86. <td>
  87. @item.CourseID
  88. </td>
  89. <td>
  90. @item.Title
  91. </td>
  92. <td>
  93. @item.Department.Name
  94. </td>
  95. </tr>
  96. }
  97.  
  98. </table>
  99. }
  100. @if (Model.Enrollments != null)
  101. {
  102. <h3>Students Enrolled in Selected Course</h3>
  103. <table>
  104. <tr>
  105. <th>Name</th>
  106. <th>Grade</th>
  107. </tr>
  108. @foreach (var item in Model.Enrollments)
  109. {
  110. <tr>
  111. <td>
  112. @item.Student.FullName
  113. </td>
  114. <td>
  115. @Html.DisplayFor(modelItem => item.Grade)
  116. </td>
  117. </tr>
  118. }
  119. </table>
  120. }

运行Instructor Index,查看效果。点击Edit查看功能,修改一些课程的分配,然后点击Save,修改结果在Index页面展示。

这种方式在课程数目不多时有效。如果课程数目很多需要修改显示方式和更新方法。

3.更新Instructor的Delete方法

修改代码,当删除教师时,为其分配的办公室信息随之删除:

  1. [HttpPost, ActionName("Delete")]
  2. [ValidateAntiForgeryToken]
  3. public ActionResult DeleteConfirmed(int id)
  4. {
  5. Instructor instructor = db.Instructors
  6. .Include(i => i.OfficeAssignment)
  7. .Where(i => i.InstructorID == id)
  8. .Single();
  9.  
  10. foreach (var department in db.Departments)
  11. {
  12. if (department.InstructorID == id)
  13. {
  14. department.InstructorID = null;
  15. }
  16. }
  17. db.Instructors.Remove(instructor);
  18. db.SaveChanges();
  19. return RedirectToAction("Index");
  20. }

已经完成了完整的CRUD操作,但没有处理同步问题。下一节将引入同步问题,介绍处理方法,为CRUD操作添加同步处理。

视频教程: 12

演练5-5:Contoso大学校园管理系统5的更多相关文章

  1. 演练5-3:Contoso大学校园管理系统3

    在前面的教程中,我们使用了一个简单的数据模型,包括三个数据实体.在这个教程汇中,我们将添加更多的实体和关系,按照特定的格式和验证规则等自定义数据模型. Contoso大学校园管理系统的数据模型如下. ...

  2. 演练5-6:Contoso大学校园管理系统6

    在上一次的教程中,我们处理了关联数据问题.这个教程演示如何处理并发问题.你将使用Department实体创建一个页面,这个页面在支持编辑和删除的同时,还可以处理并发错误.下面的截图演示了Index页面 ...

  3. 演练5-4:Contoso大学校园管理系统4

    在之前的教程中,我们已经完成了学校的数据模型.现在我们将读取和显示相关数据,请理解EF加载导航属性的方式. 一.Lazy.Eager.Explicit数据加载 使用EF为实体中的导航属性加载相关数据, ...

  4. 演练5-7:Contoso大学校园管理系统(实现继承)

    ***操作视频下载:1     *** 在上一次教程中,你已经能够处理并发异常.这个教程将会展示如何在数据模型中实现继承. 在面向对象的程序设计中,你可以通过继承来清除冗余的代码.在这个教程中,你将要 ...

  5. 演练5-8:Contoso大学校园管理系统(实现存储池和工作单元模式)

    在上一次的教程中,你已经使用继承来消除在 Student 和 Instructor 实体之间的重复代码.在这个教程中,你将要看到使用存储池和工作单元模式进行增.删.改.查的一些方法.像前面的教程一样, ...

  6. 演练5-1:Contoso大学校园管理1

    **演练目的:掌握复杂模型的应用程序开发. Contoso大学校园管理系统功能包括学生.课程.教师的管理. 一.创建MVC Web应用程序 显示效果如下图,操作步骤略. 二.创建数据模型 1.创建学生 ...

  7. 演练5-2:Contoso大学校园管理2

    一.添加列标题排序功能 我们将增加Student/Index页面的功能,为列标题添加超链接,用户可以点击列标题对那一列进行排序. 1.修改Index方法 public ActionResult Ind ...

  8. Contoso 大学 - 使用 EF Code First 创建 MVC 应用,实例演练

    Contoso 大学 Web 示例应用演示了如何使用 EF 技术创建 ASP.NET MVC 应用.示例中的 Contoso 大学是虚构的.应用包括了类似学生注册.课程创建以及教师分配等功能. 这个系 ...

  9. Contoso 大学 - 7 – 处理并发

    原文 Contoso 大学 - 7 – 处理并发 By Tom Dykstra, Tom Dykstra is a Senior Programming Writer on Microsoft's W ...

随机推荐

  1. ActionScript3游戏中的图像编程(连载十七)

    总文件夹:http://blog.csdn.net/iloveas2014/article/details/38304477 1.3.3 HSB与RGB之间的互转公式及HSL和HSV对色彩属性理解的异 ...

  2. ASP.NET中IsPostBack的理解

    IsPostBack是Page类的一个属性,返回值为一个布尔值. 一般放在Page_Load事件中, 是指是否第一次调用这个页面.当页面是第一次打开时其值为False,若当前页面为一个提交后的页面其值 ...

  3. 碰撞缓冲效果的导航条 js

  4. java中常见的单例模式详解

    很多求职者在面试过程中都被问到了单例模式,最常见的问题,比如,每种单例模式的区别是什么?哪些模式是线程安全的?你们项目里用的哪种单例模式?原来没有注意这个问题,回来赶紧打开项目查看了一下代码,才发现我 ...

  5. tasklet和工作队列

    tasklet机制和工作队列 http://blog.chinaunix.net/uid-28236237-id-3450753.html tasklet原理 http://www.kuqin.com ...

  6. 「OC」block 和 protocol

    一.block   (一)简介 block 是什么?苹果推荐的类型,效率高,在运行中保存代码.用来封装和保存代码,有点像函数,block 可以在任何时候执行.在多线程.异步任务.集合遍历.集合排序.动 ...

  7. js之form表单的获取

    js中获取form的方法: 1. 利用表单在文档中的索引或表单的name属性来引用表单 document.forms[i] //得到页面中的第i个表单 document.forms[formName] ...

  8. typeof操作符的返回值

    使用typeof操作符 对一个值使用typeof操作符可能返回下列某个字符串: 1):undefined——如果这个值未定义 2):boolean——如果这个值是布尔值 3):string——如果这个 ...

  9. C语言循环小技巧

    写代码,有两类追求,一种是追求实用(Coder),一种是追求代码艺术(Artist) 我是那种追实用追腻了,偶然追一下艺术(就是偶然和艺术有一腿)的那种Coder 很多人,已经习惯了for(i=0; ...

  10. windows apache 配置多个服务 站点 Apache Service Monitor

    把Apache安装为多个Window NT服务 ~~~ 可以在 services.msc中查看到1. 在DOS下跳到Apache安装目录里的bin目录(~~~或者用path命令 把apache的安装目 ...