共用方式為


使用 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 不會直接公開聯結數據表,因此您必須明確地在適當的導覽屬性中新增和移除實體。

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

顯示 [建立課程] 頁面的螢幕快照。

顯示講師編輯頁面的螢幕快照。

自訂 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尋找具名 DepartmentIDSelectList

方法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);
}

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

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.cshtml、Views\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

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

為講師新增編輯頁面

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

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

開啟 InstructorController.cs 並查看 HttpGet Edit 方法:

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 方法來選取講師。

HttpPost Edit以下列程序代碼取代 方法。 處理辦公室指派更新:

[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 實體。 這與您在 HttpGet Edit 方法中所做的相同。

  • 使用從模型繫結器取得的值更新擷取的 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>

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

Changing_the_office_location

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

講師可教授任何數量的課程。 現在您將藉由使用核取方塊群組,新增變更課程指派的能力來強化 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 檢視。

接下來,新增當使用者按一下 [儲存] 時要執行的程式碼。 HttpPost Edit將方法取代為下列程式代碼,它會呼叫更新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 而且不在 include 清單中。

如果未選取複選框,中的 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 對象,因為您想要顯示的信息已經位於 Courses 您傳遞至頁面做為模型的實體導覽屬性 Instructor 中。

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_index_page

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

Instructor_edit_page_with_courses

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

注意:當課程數量有限時,編輯講師課程數據的方法可正常運作。 針對更大的集合,將需要不同的 UI 和不同的更新方法。

更新 Delete 方法

變更 HttpPost Delete 方法中的程式碼,以便在刪除講師時刪除辦公室指派記錄(如果有的話):

[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 資源的連結。