使用 ASP.NET MVC 應用程式中的 Entity Framework 更新相關資料, (6/10)

作者 :Tom Dykstra

Contoso University 範例 Web 應用程式示範如何使用 Entity Framework 5 Code First 和 Visual Studio 2012 建立 ASP.NET MVC 4 應用程式。 如需教學課程系列的資訊,請參閱本系列的第一個教學課程

注意

如果您遇到無法解決的問題,請 下載已完成的章節 並嘗試重現您的問題。 一般而言,您可以將程式碼與已完成的程式碼進行比較,以找出問題的解決方案。 如需一些常見的錯誤以及如何解決這些問題,請參閱 錯誤和因應措施。

在上一個教學課程中,您已顯示相關資料;在本教學課程中,您將更新相關資料。 對於大部分的關聯性,可以藉由更新適當的外鍵欄位來完成。 針對多對多關聯性,Entity Framework 不會直接公開聯結資料表,因此您必須明確地在適當的導覽屬性中新增和移除實體。

下列圖例顯示了您將操作的頁面。

顯示 [建立課程] 頁面的螢幕擷取畫面。

顯示 Instructor 編輯頁面的螢幕擷取畫面。

自訂 Courses 的 [建立] 和 [編輯] 頁面

當新的課程實體建立時,其必須要與現有的部門具有關聯性。 若要達成此目的,Scaffold 程式碼包含了控制器方法和 [建立] 和 [編輯] 檢視,當中包含了一個可選取部門的下拉式清單。 下拉式清單會 Course.DepartmentID 設定外鍵屬性,而且這是所有 Entity Framework 都需要的,才能使用適當的 Department 實體載入 Department 導覽屬性。 您將使用 Scaffold 程式碼,但會稍微對其進行一些變更以新增錯誤處理及排序下拉式清單。

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

方法會 HttpGetCreate 呼叫 PopulateDepartmentsDropDownList 方法,而不設定選取的專案,因為對於尚未建立部門的新課程:

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

方法 HttpGetEdit 會根據已指派給所編輯課程的部門識別碼,設定選取的專案:

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

HttpPostEdit 的方法 Create 也包含程式碼,這些程式碼會在錯誤之後重新顯示頁面時設定選取的專案:

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中,新增醒目提示的程式碼,以在 [標題 ] 欄位之前建立新的課程編號欄位。 如先前教學課程所述,預設不會建構主鍵欄位,但此主鍵有意義,因此您希望使用者能夠輸入索引鍵值。

@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.cshtmlViews\Course\Delete.cshtmlViews\Course\Details.cshtml中,于 [標題 ] 欄位之前新增課程編號欄位。 因為它是主鍵,所以會顯示它,但無法變更。

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

執行 [ 建立 ] 頁面 (顯示 [課程索引] 頁面,然後按一下 [ 建立新) ],然後輸入新課程的資料:

Course_create_page

按一下 [建立]。 [課程索引] 頁面會顯示新增至清單的新課程。 [索引] 頁面中的部門名稱來自於導覽屬性,顯示關聯性已正確建立。

Course_Index_page_showing_new_course

執行 [ 編輯 ] 頁面 (顯示 [課程索引] 頁面,然後按一下課程) 上的 [編輯 ]。

Course_edit_page

變更頁面上的資料,然後按一下 [儲存]。 [課程索引] 頁面會顯示已更新的課程資料。

新增 Instructors 的編輯頁面

當您編輯講師記錄時,您可能會想要更新講師的辦公室指派。 實體 Instructor 與實體具有一對零或一的關聯性 OfficeAssignment ,這表示您必須處理下列情況:

  • 如果使用者清除辦公室工作分派,且原先有值,您必須移除和刪除 OfficeAssignment 實體。
  • 如果使用者輸入辦公室工作分派值,且原本是空的,您必須建立新的 OfficeAssignment 實體。
  • 如果使用者變更辦公室指派的值,您必須變更現有 OfficeAssignment 實體中的值。

開啟InstructorController.cs並查看 HttpGetEdit 方法:

public ActionResult Edit(int id = 0)
{
    Instructor instructor = db.Instructors.Find(id);
    if (instructor == null)
    {
        return HttpNotFound();
    }
    ViewBag.InstructorID = new SelectList(db.OfficeAssignments, "InstructorID", "Location", instructor.InstructorID);
    return View(instructor);
}

此處的 Scaffold 程式碼不是您想要的程式碼。 它會設定下拉式清單的資料,但您需要的是文字方塊。 將此方法取代為下列程式碼:

public ActionResult Edit(int id)
{
    Instructor instructor = db.Instructors
        .Include(i => i.OfficeAssignment)
        .Where(i => i.InstructorID == id)
        .Single();
    return View(instructor);
}

此程式碼會卸載 語句, ViewBag 並為相關聯的 OfficeAssignment 實體新增積極式載入。 您無法使用 Find 方法執行積極式載入,因此 Where 會改用 和 Single 方法來選取講師。

HttpPostEdit 方法取代為下列程式碼。 可處理辦公室指派更新:

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(int id, FormCollection formCollection)
{
   var instructorToUpdate = db.Instructors
       .Include(i => i.OfficeAssignment)
       .Where(i => i.InstructorID == id)
       .Single();

   if (TryUpdateModel(instructorToUpdate, "",
      new string[] { "LastName", "FirstMidName", "HireDate", "OfficeAssignment" }))
   {
      try
      {
         if (String.IsNullOrWhiteSpace(instructorToUpdate.OfficeAssignment.Location))
         {
            instructorToUpdate.OfficeAssignment = null;
         }

         db.Entry(instructorToUpdate).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.");
      }
   }
   ViewBag.InstructorID = new SelectList(db.OfficeAssignments, "InstructorID", "Location", id);
   return View(instructorToUpdate);
}

此程式碼會執行下列動作:

  • 針對 OfficeAssignment 導覽屬性使用積極式載入從資料庫中取得目前的 Instructor 實體。 這與您在 HttpGetEdit 方法中所做的相同。

  • 使用從模型繫結器取得的值更新擷取的 Instructor 實體。 使用的 TryUpdateModel 多載可讓您 安全地列出 您想要包含的屬性。 這可防止過度張貼,如 第二個教學課程中所述。

    if (TryUpdateModel(instructorToUpdate, "",
          new string[] { "LastName", "FirstMidName", "HireDate", "OfficeAssignment" }))
    
  • 如果辦公室位置是空白的,請將 Instructor.OfficeAssignment 屬性設定為 null,以便刪除資料表中的 OfficeAssignment 相關資料列。

    if (String.IsNullOrWhiteSpace(instructorToUpdate.OfficeAssignment.Location))
    {
        instructorToUpdate.OfficeAssignment = null;
    }
    
  • 將變更儲存到資料庫。

Views\Instructor\Edit.cshtml中,于[雇用日期] 欄位的元素之後 div ,新增欄位以編輯辦公室位置:

<div class="editor-label">
    @Html.LabelFor(model => model.OfficeAssignment.Location)
</div>
<div class="editor-field">
    @Html.EditorFor(model => model.OfficeAssignment.Location)
    @Html.ValidationMessageFor(model => model.OfficeAssignment.Location)
</div>

執行頁面 (選取 [Instructors ] 索引標籤,然後按一下講師) 上的 [編輯 ]。 變更 [辦公室位置],然後按一下 [儲存]

Changing_the_office_location

將課程指派新增至 Instructor 編輯頁面

講師可教授任何數量的課程。 現在您將藉由使用核取方塊群組,新增變更課程指派的能力來強化 Instructor [編輯] 頁面,如以下螢幕擷取畫面所示:

顯示講師編輯頁面與課程的螢幕擷取畫面。

Instructor 實體之間的 Course 關聯性是多對多,這表示您沒有聯結資料表的直接存取權。 相反地,您會在導覽屬性中 Instructor.Courses 新增和移除實體。

可讓您變更講師指派之課程的 UI 為一組核取方塊。 資料庫中每個課程的核取方塊都會顯示,而該名講師目前受指派的課程會已選取狀態顯示。 使用者可選取或清除核取方塊來變更課程指派。 如果課程數目更大,您可能想要使用不同的方法來呈現檢視中的資料,但您會使用相同的方法來操作導覽屬性,以建立或刪除關聯性。

若要針對核取方塊清單提供資料給檢視,您必須使用一個檢視模型類別。 在ViewModels資料夾中建立AssignedCourseData.cs,並以下列程式碼取代現有的程式碼:

namespace ContosoUniversity.ViewModels
{
    public class AssignedCourseData
    {
        public int CourseID { get; set; }
        public string Title { get; set; }
        public bool Assigned { get; set; }
    }
}

InstructorController.cs中,以下列程式碼取代 HttpGetEdit 方法。 所做的變更已醒目提示。

public ActionResult Edit(int id)
{
    Instructor instructor = db.Instructors
        .Include(i => i.OfficeAssignment)
        .Include(i => i.Courses)
        .Where(i => i.InstructorID == id)
        .Single();
    PopulateAssignedCourseData(instructor);
    return View(instructor);
}

private void PopulateAssignedCourseData(Instructor instructor)
{
    var allCourses = db.Courses;
    var instructorCourses = new HashSet<int>(instructor.Courses.Select(c => c.CourseID));
    var viewModel = new List<AssignedCourseData>();
    foreach (var course in allCourses)
    {
        viewModel.Add(new AssignedCourseData
        {
            CourseID = course.CourseID,
            Title = course.Title,
            Assigned = instructorCourses.Contains(course.CourseID)
        });
    }
    ViewBag.Courses = viewModel;
}

程式碼會為 Courses 導覽屬性新增積極式載入,然後使用 AssignedCourseData 檢視模型類別來呼叫新的 PopulateAssignedCourseData 方法以提供資訊給核取方塊陣列。

方法中的 PopulateAssignedCourseData 程式碼會讀取所有 Course 實體,以使用檢視模型類別載入課程清單。 針對每個課程,程式碼會檢查課程是否存在於講師的 Courses 導覽屬性中。 若要在檢查課程是否已指派給講師時建立有效率的查閱,指派給講師的課程會放入 HashSet 集合中。 屬性 Assigned 會針對指派講師的課程設定 true 為 。 檢視會使用這個屬性,來判斷哪一個核取方塊必須顯示為已選取。 最後,清單會傳遞至 屬性中的 ViewBag 檢視。

接下來,新增當使用者按一下 [儲存] 時要執行的程式碼。 將 HttpPostEdit 方法取代為下列程式碼,它會呼叫更新 Courses 實體導覽屬性 Instructor 的新方法。 所做的變更已醒目提示。

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(int id, FormCollection formCollection, string[] selectedCourses)
{
   var instructorToUpdate = db.Instructors
       .Include(i => i.OfficeAssignment)
       .Include(i => i.Courses)
       .Where(i => i.InstructorID == id)
       .Single();
   if (TryUpdateModel(instructorToUpdate, "", 
      new string[] { "LastName", "FirstMidName", "HireDate", "OfficeAssignment" }))
   {
      try
      {
         if (String.IsNullOrWhiteSpace(instructorToUpdate.OfficeAssignment.Location))
         {
            instructorToUpdate.OfficeAssignment = null;
         }

         UpdateInstructorCourses(selectedCourses, instructorToUpdate);

         db.Entry(instructorToUpdate).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.");
      }
   }
   PopulateAssignedCourseData(instructorToUpdate);
   return View(instructorToUpdate);
}

private void UpdateInstructorCourses(string[] selectedCourses, Instructor instructorToUpdate)
{
   if (selectedCourses == null)
   {
      instructorToUpdate.Courses = new List<Course>();
      return;
   }

   var selectedCoursesHS = new HashSet<string>(selectedCourses);
   var instructorCourses = new HashSet<int>
       (instructorToUpdate.Courses.Select(c => c.CourseID));
   foreach (var course in db.Courses)
   {
      if (selectedCoursesHS.Contains(course.CourseID.ToString()))
      {
         if (!instructorCourses.Contains(course.CourseID))
         {
            instructorToUpdate.Courses.Add(course);
         }
      }
      else
      {
         if (instructorCourses.Contains(course.CourseID))
         {
            instructorToUpdate.Courses.Remove(course);
         }
      }
   }
}

由於檢視沒有實體集合 Course ,因此模型系結器無法自動更新 Courses 導覽屬性。 您不會使用模型系結器來更新 Courses 導覽屬性,而是在新的 UpdateInstructorCourses 方法中執行此動作。 因此您必須從模型繫結器中排除 Courses 屬性。 這不需要對呼叫 TryUpdateModel 的程式碼進行任何變更,因為您使用的是 安全清單 多載,而且 Courses 不在包含清單中。

如果未選取任何核取方塊,中的 UpdateInstructorCourses 程式碼會使用空集合初始化 Courses 導覽屬性:

if (selectedCourses == null)
{
    instructorToUpdate.Courses = new List<Course>();
    return;
}

程式碼會執行迴圈,尋訪資料庫中所有的課程,並檢查每個已指派給講師的課程,以及在檢視中選取的課程。 為了協助達成有效率的搜尋,後者的兩個集合會儲存在 HashSet 物件中。

若課程的核取方塊已被選取,但課程並未位於 Instructor.Courses 導覽屬性中,則課程便會新增至導覽屬性的集合中。

if (selectedCoursesHS.Contains(course.CourseID.ToString()))
{
    if (!instructorCourses.Contains(course.CourseID))
    {
        instructorToUpdate.Courses.Add(course);
    }
}

若課程的核取方塊未被選取,但課程卻位於 Instructor.Courses 導覽屬性中,則課程便會從導覽屬性的集合中移除。

else
{
    if (instructorCourses.Contains(course.CourseID))
    {
        instructorToUpdate.Courses.Remove(course);
    }
}

Views\Instructor\Edit.cshtml中,新增具有核取方塊陣列的Courses欄位,方法是在欄位的元素 OfficeAssignment 後面 div 立即新增下列醒目提示的程式碼:

@model ContosoUniversity.Models.Instructor

@{
    ViewBag.Title = "Edit";
}

<h2>Edit</h2>

@using (Html.BeginForm())
{
    @Html.AntiForgeryToken()
    @Html.ValidationSummary(true)

    <fieldset>
        <legend>Instructor</legend>

        @Html.HiddenFor(model => model.InstructorID)

        <div class="editor-label">
            @Html.LabelFor(model => model.LastName)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.LastName)
            @Html.ValidationMessageFor(model => model.LastName)
        </div>

        <div class="editor-label">
            @Html.LabelFor(model => model.FirstMidName)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.FirstMidName)
            @Html.ValidationMessageFor(model => model.FirstMidName)
        </div>

        <div class="editor-label">
            @Html.LabelFor(model => model.HireDate)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.HireDate)
            @Html.ValidationMessageFor(model => model.HireDate)
        </div>

        <div class="editor-label">
            @Html.LabelFor(model => model.OfficeAssignment.Location)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.OfficeAssignment.Location)
            @Html.ValidationMessageFor(model => model.OfficeAssignment.Location)
        </div>

        <div class="editor-field">
    <table>
        <tr>
            @{
                int cnt = 0;
                List<ContosoUniversity.ViewModels.AssignedCourseData> courses = ViewBag.Courses;

                foreach (var course in courses) {
                    if (cnt++ % 3 == 0) {
                        @:  </tr> <tr> 
                    }
                    @: <td> 
                        <input type="checkbox" 
                               name="selectedCourses" 
                               value="@course.CourseID" 
                               @(Html.Raw(course.Assigned ? "checked=\"checked\"" : "")) /> 
                        @course.CourseID @:  @course.Title
                    @:</td>
                }
                @: </tr>
            }
    </table>
</div>
        <p>
            <input type="submit" value="Save" />
        </p>
    </fieldset>
}

<div>
    @Html.ActionLink("Back to List", "Index")
</div>

@section Scripts {
    @Scripts.Render("~/bundles/jqueryval")
}

此程式碼會建立一個 HTML 表格,該表格中有三個資料行。 在每個資料行中,核取方塊的後方會是由課程號碼和標題組成的標題。 核取方塊全都有相同的名稱 (「selectedCourses」) ,這會通知模型系結器將它們視為群組。 value每個核取方塊的 屬性都會設定為 [張貼頁面時] 的值 CourseID. ,模型系結器會將陣列傳遞至控制器,該控制器只包含 CourseID 所選取核取方塊的值。

一開始轉譯核取方塊時,指派給講師 checked 的課程會有屬性,這會選取它們 (顯示已核取) 。

變更課程指派之後,您希望能夠在網站返回 Index 頁面時驗證變更。 因此,您必須將資料行新增至該頁面中的資料表。 在此情況下,您不需要使用 ViewBag 物件,因為您想要顯示的資訊已經在您傳遞至頁面做為模型的實體導覽屬性 InstructorCourses

Views\Instructor\Index.cshtml中,緊接在Office標題後面新增Courses標題,如下列範例所示:

<tr> 
    <th></th> 
    <th>Last Name</th> 
    <th>First Name</th> 
    <th>Hire Date</th> 
    <th>Office</th>
    <th>Courses</th>
</tr>

然後緊接在辦公室位置詳細資料格後面新增詳細資料格:

@model ContosoUniversity.ViewModels.InstructorIndexData

@{
    ViewBag.Title = "Instructors";
}

<h2>Instructors</h2>

<p>
    @Html.ActionLink("Create New", "Create")
</p>
<table>
    <tr>
        <th></th>
        <th>Last Name</th>
        <th>First Name</th>
        <th>Hire Date</th>
        <th>Office</th>
        <th>Courses</th>
    </tr>
    @foreach (var item in Model.Instructors)
    {
        string selectedRow = "";
        if (item.InstructorID == ViewBag.InstructorID)
        {
            selectedRow = "selectedrow";
        } 
        <tr class="@selectedRow" valign="top">
            <td>
                @Html.ActionLink("Select", "Index", new { id = item.InstructorID }) | 
                @Html.ActionLink("Edit", "Edit", new { id = item.InstructorID }) | 
                @Html.ActionLink("Details", "Details", new { id = item.InstructorID }) | 
                @Html.ActionLink("Delete", "Delete", new { id = item.InstructorID })
            </td>
            <td>
                @item.LastName
            </td>
            <td>
                @item.FirstMidName
            </td>
            <td>
                @String.Format("{0:d}", item.HireDate)
            </td>
            <td>
                @if (item.OfficeAssignment != null)
                { 
                    @item.OfficeAssignment.Location  
                }
            </td>
            <td>
                @{
                foreach (var course in item.Courses)
                {
                    @course.CourseID @:  @course.Title <br />
                }
                }
            </td>
        </tr> 
    }
</table>

@if (Model.Courses != null)
{ 
    <h3>Courses Taught by Selected Instructor</h3> 
    <table>
        <tr>
            <th></th>
            <th>ID</th>
            <th>Title</th>
            <th>Department</th>
        </tr>

        @foreach (var item in Model.Courses)
        {
            string selectedRow = "";
            if (item.CourseID == ViewBag.CourseID)
            {
                selectedRow = "selectedrow";
            } 
        
            <tr class="@selectedRow">

                <td>
                    @Html.ActionLink("Select", "Index", new { courseID = item.CourseID })
                </td>
                <td>
                    @item.CourseID
                </td>
                <td>
                    @item.Title
                </td>
                <td>
                    @item.Department.Name
                </td>
            </tr> 
        }

    </table> 
}
@if (Model.Enrollments != null)
{ 
    <h3>Students Enrolled in Selected Course</h3> 
    <table>
        <tr>
            <th>Name</th>
            <th>Grade</th>
        </tr>
        @foreach (var item in Model.Enrollments)
        { 
            <tr>
                <td>
                    @item.Student.FullName
                </td>
                <td>
                    @Html.DisplayFor(modelItem => item.Grade)
                </td>
            </tr> 
        }
    </table> 
}

執行 Instructor 索引 頁面,以查看指派給每個講師的課程:

Instructor_index_page

按一下講師上的 [編輯 ] 以查看 [編輯] 頁面。

Instructor_edit_page_with_courses

變更一些課程指派,然後按一下 [ 儲存]。 您所做的變更會反映在 [索引] 頁面上。

注意:編輯講師課程資料的方法在課程數量有限時運作良好。 針對更大的集合,將需要不同的 UI 和不同的更新方法。

更新 Delete 方法

變更 HttpPost Delete 方法中的程式碼,以便在刪除講師時刪除任何) 時,office 工作分派記錄 (:

[HttpPost, ActionName("Delete")]
[ValidateAntiForgeryToken]
public ActionResult DeleteConfirmed(int id)
{
   Instructor instructor = db.Instructors
     .Include(i => i.OfficeAssignment)
     .Where(i => i.InstructorID == id)
     .Single();

   instructor.OfficeAssignment = null;
   db.Instructors.Remove(instructor);
   db.SaveChanges();
   return RedirectToAction("Index");
}

如果您嘗試以系統管理員身分刪除指派給部門的講師,您將會收到參考完整性錯誤。 如需將講師指派為系統管理員的任何部門自動移除講師的其他程式碼,請參閱 本教學課程的目前版本

總結

您現在已完成這項使用相關資料的簡介。 到目前為止,在這些教學課程中,您已完成完整的 CRUD 作業,但您尚未處理並行問題。 下一個教學課程將介紹並行的主題、說明處理它的選項,並將並行處理新增至您已針對一個實體類型撰寫的 CRUD 程式碼。

您可以在 本系列最後一個教學課程結尾找到其他 Entity Framework 資源的連結。