Bagikan melalui


Memperbarui Data Terkait dengan Kerangka Kerja Entitas dalam Aplikasi MVC ASP.NET (6 dari 10)

oleh Tom Dykstra

Aplikasi web sampel Contoso University menunjukkan cara membuat aplikasi ASP.NET MVC 4 menggunakan Entity Framework 5 Code First dan Visual Studio 2012. Untuk informasi tentang seri tutorial, lihat tutorial pertama dalam seri ini.

Catatan

Jika Anda mengalami masalah yang tidak dapat Anda atasi, unduh bab yang telah selesai dan coba reprodurasi masalah Anda. Anda umumnya dapat menemukan solusi untuk masalah dengan membandingkan kode Anda dengan kode yang telah selesai. Untuk beberapa kesalahan umum dan cara mengatasinya, lihat Kesalahan dan Solusi.

Dalam tutorial sebelumnya Anda menampilkan data terkait; dalam tutorial ini Anda akan memperbarui data terkait. Untuk sebagian besar hubungan, ini dapat dilakukan dengan memperbarui bidang kunci asing yang sesuai. Untuk hubungan banyak ke banyak, Kerangka Kerja Entitas tidak mengekspos tabel gabungan secara langsung, jadi Anda harus secara eksplisit menambahkan dan menghapus entitas ke dan dari properti navigasi yang sesuai.

Ilustrasi berikut ini memperlihatkan halaman yang akan Anda kerjakan.

Cuplikan layar yang memperlihatkan halaman Buat Kursus.

Cuplikan layar yang menampilkan halaman Edit Instruktur.

Mengkustomisasi Buat dan Edit Halaman untuk Kursus

Ketika entitas kursus baru dibuat, entitas tersebut harus memiliki hubungan dengan departemen yang ada. Untuk memfasilitasi hal ini, kode perancah mencakup metode pengontrol dan Membuat dan Mengedit tampilan yang menyertakan daftar drop-down untuk memilih departemen. Daftar drop-down mengatur Course.DepartmentID properti kunci asing, dan itu semua yang dibutuhkan Kerangka Kerja Entitas untuk memuat Department properti navigasi dengan entitas yang sesuai Department . Anda akan menggunakan kode perancah, tetapi mengubahnya sedikit untuk menambahkan penanganan kesalahan dan mengurutkan daftar drop-down.

Dalam CourseController.cs, hapus empat Edit metode dan Create dan ganti dengan kode berikut:

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

Metode ini PopulateDepartmentsDropDownList mendapatkan daftar semua departemen yang diurutkan menurut nama, membuat SelectList koleksi untuk daftar drop-down, dan meneruskan koleksi ke tampilan dalam ViewBag properti. Metode ini menerima parameter opsional selectedDepartment yang memungkinkan kode panggilan menentukan item yang akan dipilih saat daftar drop-down dirender. Tampilan akan meneruskan nama DepartmentID ke DropDownList pembantu, dan pembantu kemudian tahu untuk mencari ViewBag objek untuk bernama SelectList DepartmentID.

Metode HttpGet Create memanggil PopulateDepartmentsDropDownList metode tanpa mengatur item yang dipilih, karena untuk kursus baru departemen belum ditetapkan:

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

Metode HttpGet Edit ini mengatur item yang dipilih, berdasarkan ID departemen yang sudah ditetapkan ke kursus yang sedang diedit:

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

Metode HttpPost untuk keduanya Create dan Edit juga menyertakan kode yang mengatur item yang dipilih saat mereka memutar ulang halaman setelah kesalahan:

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);

Kode ini memastikan bahwa ketika halaman diputar ulang untuk menampilkan pesan kesalahan, departemen apa pun yang dipilih tetap dipilih.

Di Views\Course\Create.cshtml, tambahkan kode yang disorot untuk membuat bidang nomor kursus baru sebelum bidang Judul . Seperti yang dijelaskan dalam tutorial sebelumnya, bidang kunci primer tidak dibuat secara default, tetapi kunci utama ini bermakna, jadi Anda ingin pengguna dapat memasukkan nilai kunci.

@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")
}

Di Views\Course\Edit.cshtml, Views\Course\Delete.cshtml, dan Views\Course\Details.cshtml, tambahkan bidang nomor kursus sebelum bidang Judul . Karena ini adalah kunci utama, kunci tersebut ditampilkan, tetapi tidak dapat diubah.

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

Jalankan halaman Buat (tampilkan halaman Indeks Kursus dan klik Buat Baru) dan masukkan data untuk kursus baru:

Course_create_page

Klik Buat. Halaman Indeks Kursus ditampilkan dengan kursus baru ditambahkan ke daftar. Nama departemen dalam daftar halaman Indeks berasal dari properti navigasi, memperlihatkan bahwa hubungan dibuat dengan benar.

Course_Index_page_showing_new_course

Jalankan halaman Edit (tampilkan halaman Indeks Kursus dan klik Edit pada kursus).

Course_edit_page

Ubah data di halaman dan klik Simpan. Halaman Indeks Kursus ditampilkan dengan data kursus yang diperbarui.

Menambahkan Halaman Edit untuk Instruktur

Saat mengedit catatan instruktur, Anda ingin dapat memperbarui penetapan kantor instruktur. Entitas Instructor memiliki hubungan satu-ke-nol-atau-satu dengan OfficeAssignment entitas, yang berarti Anda harus menangani situasi berikut:

  • Jika pengguna menghapus penetapan office dan awalnya memiliki nilai, Anda harus menghapus dan menghapus OfficeAssignment entitas.
  • Jika pengguna memasukkan nilai penetapan kantor dan awalnya kosong, Anda harus membuat entitas baru OfficeAssignment .
  • Jika pengguna mengubah nilai penetapan office, Anda harus mengubah nilai di entitas yang ada OfficeAssignment .

Buka InstructorController.cs dan lihat metode :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);
}

Kode perancah di sini bukan yang Anda inginkan. Ini menyiapkan data untuk daftar drop-down, tetapi Anda yang Anda butuhkan adalah kotak teks. Ganti metode ini dengan kode berikut:

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

Kode ini menghilangkan ViewBag pernyataan dan menambahkan pemuatan yang bersemangat untuk entitas terkait OfficeAssignment . Anda tidak dapat melakukan pemuatan bersemangat dengan Find metode , sehingga Where metode dan Single digunakan sebagai gantinya untuk memilih instruktur.

HttpPost Edit Ganti metode dengan kode berikut. yang menangani pembaruan penetapan kantor:

[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);
}

Kode melakukan hal berikut:

  • Mendapatkan entitas saat ini Instructor dari database menggunakan pemuatan bersemangat untuk OfficeAssignment properti navigasi. Ini sama dengan apa yang Anda lakukan dalam HttpGet Edit metode .

  • Memperbarui entitas yang diambil Instructor dengan nilai dari pengikat model. Kelebihan beban TryUpdateModel yang digunakan memungkinkan Anda untuk membuat daftar properti yang ingin Anda sertakan dengan aman . Ini mencegah pengiriman berlebihan, seperti yang dijelaskan dalam tutorial kedua.

    if (TryUpdateModel(instructorToUpdate, "",
          new string[] { "LastName", "FirstMidName", "HireDate", "OfficeAssignment" }))
    
  • Jika lokasi kantor kosong, atur Instructor.OfficeAssignment properti ke null sehingga baris terkait dalam OfficeAssignment tabel akan dihapus.

    if (String.IsNullOrWhiteSpace(instructorToUpdate.OfficeAssignment.Location))
    {
        instructorToUpdate.OfficeAssignment = null;
    }
    
  • Menyimpan perubahan ke database.

Di Views\Instructor\Edit.cshtml, setelah div elemen untuk bidang Tanggal Sewa, tambahkan bidang baru untuk mengedit lokasi kantor:

<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>

Jalankan halaman (pilih tab Instruktur lalu klik Edit pada instruktur). Ubah Lokasi Office dan klik Simpan.

Changing_the_office_location

Menambahkan Tugas Kursus ke Halaman Edit Instruktur

Instruktur dapat mengajarkan sejumlah kursus. Sekarang Anda akan menyempurnakan halaman Edit Instruktur dengan menambahkan kemampuan untuk mengubah penetapan kursus menggunakan sekelompok kotak centang, seperti yang ditunjukkan dalam cuplikan layar berikut:

Cuplikan layar yang memperlihatkan halaman Edit Instruktur dengan kursus.

Hubungan antara Course entitas dan Instructor adalah banyak-ke-banyak, yang berarti Anda tidak memiliki akses langsung ke tabel gabungan. Sebagai gantinya, Anda akan menambahkan dan menghapus entitas ke dan dari Instructor.Courses properti navigasi.

UI yang memungkinkan Anda mengubah kursus mana yang ditetapkan instruktur adalah sekelompok kotak centang. Kotak centang untuk setiap kursus dalam database ditampilkan, dan kotak centang yang saat ini ditetapkan instruktur dipilih. Pengguna dapat memilih atau menghapus kotak centang untuk mengubah penetapan kursus. Jika jumlah kursus jauh lebih besar, Anda mungkin ingin menggunakan metode yang berbeda untuk menyajikan data dalam tampilan, tetapi Anda akan menggunakan metode yang sama untuk memanipulasi properti navigasi untuk membuat atau menghapus hubungan.

Untuk menyediakan data ke tampilan untuk daftar kotak centang, Anda akan menggunakan kelas model tampilan. Buat AssignedCourseData.cs di folder ViewModels dan ganti kode yang ada dengan kode berikut:

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

Di InstructorController.cs, ganti HttpGet Edit metode dengan kode berikut. Perubahan disorot.

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;
}

Kode menambahkan pemuatan bersemangat untuk Courses properti navigasi dan memanggil metode baru PopulateAssignedCourseData untuk memberikan informasi untuk array kotak centang menggunakan AssignedCourseData kelas model tampilan.

Kode dalam PopulateAssignedCourseData metode membaca semua Course entitas untuk memuat daftar kursus menggunakan kelas model tampilan. Untuk setiap kursus, kode memeriksa apakah kursus ada di properti navigasi instruktur Courses . Untuk membuat pencarian yang efisien saat memeriksa apakah kursus ditetapkan ke instruktur, kursus yang ditetapkan ke instruktur dimasukkan ke dalam koleksi HashSet . Properti Assigned diatur ke true untuk kursus yang ditetapkan instruktur. Tampilan akan menggunakan properti ini untuk menentukan kotak centang mana yang harus ditampilkan seperti yang dipilih. Terakhir, daftar diteruskan ke tampilan dalam ViewBag properti.

Selanjutnya, tambahkan kode yang dijalankan saat pengguna mengklik Simpan. HttpPost Edit Ganti metode dengan kode berikut, yang memanggil metode baru yang memperbarui Courses properti Instructor navigasi entitas. Perubahan disorot.

[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);
         }
      }
   }
}

Karena tampilan tidak memiliki kumpulan Course entitas, pengikat model tidak dapat memperbarui Courses properti navigasi secara otomatis. Alih-alih menggunakan pengikat model untuk memperbarui properti navigasi Kursus, Anda akan melakukannya dalam metode baru UpdateInstructorCourses . Oleh karena itu Anda perlu mengecualikan Courses properti dari pengikatan model. Ini tidak memerlukan perubahan apa pun pada kode yang memanggil TryUpdateModel karena Anda menggunakan daftar aman kelebihan beban dan Courses tidak ada dalam daftar sertakan.

Jika tidak ada kotak centang yang dipilih, kode dalam UpdateInstructorCourses menginisialisasi Courses properti navigasi dengan koleksi kosong:

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

Kode kemudian mengulangi semua kursus dalam database dan memeriksa setiap kursus terhadap yang saat ini ditetapkan ke instruktur versus yang dipilih dalam tampilan. Untuk memfasilitasi pencarian yang efisien, dua koleksi terakhir disimpan dalam HashSet objek.

Jika kotak centang untuk kursus dipilih tetapi kursus tidak berada di Instructor.Courses properti navigasi, kursus ditambahkan ke koleksi di properti navigasi.

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

Jika kotak centang untuk kursus tidak dipilih, tetapi kursus berada di Instructor.Courses properti navigasi, kursus dihapus dari properti navigasi.

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

Di Views\Instructor\Edit.cshtml, tambahkan bidang Kursus dengan array kotak centang dengan menambahkan kode yang disorot berikut segera setelah div elemen untuk OfficeAssignment bidang :

@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")
}

Kode ini membuat tabel HTML yang memiliki tiga kolom. Di setiap kolom adalah kotak centang diikuti dengan keterangan yang terdiri dari nomor kursus dan judul. Kotak centang semuanya memiliki nama yang sama ("selectedCourses"), yang menginformasikan pengikat model bahwa mereka akan diperlakukan sebagai grup. Atribut value setiap kotak centang diatur ke nilai CourseID. Saat halaman diposting, pengikat model meneruskan array ke pengontrol yang terdiri dari CourseID nilai hanya untuk kotak centang yang dipilih.

Ketika kotak centang awalnya dirender, kotak centang yang untuk kursus yang ditetapkan ke instruktur memiliki checked atribut, yang memilihnya (menampilkannya dicentang).

Setelah mengubah penetapan kursus, Anda mungkin ingin dapat memverifikasi perubahan saat situs kembali ke Index halaman. Oleh karena itu, Anda perlu menambahkan kolom ke tabel di halaman tersebut. Dalam hal ini Anda tidak perlu menggunakan ViewBag objek, karena informasi yang ingin Anda tampilkan sudah berada di Courses properti Instructor navigasi entitas yang Anda teruskan ke halaman sebagai model.

Di Views\Instructor\Index.cshtml, tambahkan judul Kursus segera mengikuti judul Office , seperti yang diperlihatkan dalam contoh berikut:

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

Kemudian tambahkan sel detail baru segera mengikuti sel detail lokasi kantor:

@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> 
}

Jalankan halaman Indeks Instruktur untuk melihat kursus yang ditetapkan untuk setiap instruktur:

Instructor_index_page

Klik Edit pada instruktur untuk melihat halaman Edit.

Instructor_edit_page_with_courses

Ubah beberapa tugas kursus dan klik Simpan. Perubahan yang Anda buat tercermin pada halaman Indeks.

Catatan: Pendekatan yang diambil untuk mengedit data kursus instruktur berfungsi dengan baik ketika ada sejumlah kursus yang terbatas. Untuk koleksi yang jauh lebih besar, UI yang berbeda dan metode pembaruan yang berbeda akan diperlukan.

Memperbarui Metode Penghapusan

Ubah kode dalam metode Hapus HttpPost sehingga catatan penetapan office (jika ada) dihapus saat instruktur dihapus:

[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");
}

Jika Anda mencoba menghapus instruktur yang ditetapkan ke departemen sebagai administrator, Anda akan mendapatkan kesalahan integritas referensial. Lihat versi tutorial ini saat ini untuk kode tambahan yang akan secara otomatis menghapus instruktur dari departemen mana pun di mana instruktur ditetapkan sebagai administrator.

Ringkasan

Anda sekarang telah menyelesaikan pengenalan ini untuk bekerja dengan data terkait. Sejauh ini dalam tutorial ini Anda telah melakukan berbagai operasi CRUD, tetapi Anda belum berurusan dengan masalah konkurensi. Tutorial berikutnya akan memperkenalkan topik konkurensi, menjelaskan opsi untuk menanganinya, dan menambahkan penanganan konkurensi ke kode CRUD yang telah Anda tulis untuk satu jenis entitas.

Tautan ke sumber daya Entity Framework lainnya, dapat ditemukan di akhir tutorial terakhir dalam seri ini.