Bagikan melalui


Tutorial: Memperbarui data terkait dengan EF di aplikasi MVC ASP.NET

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 atau properti navigasi. Untuk hubungan banyak ke banyak, Kerangka Kerja Entitas tidak mengekspos tabel gabungan secara langsung, sehingga Anda menambahkan dan menghapus entitas ke dan dari properti navigasi yang sesuai.

Ilustrasi berikut ini memperlihatkan beberapa halaman yang akan Anda kerjakan.

Course_create_page

Instructor_edit_page_with_courses

Edit instruktur dengan kursus

Di tutorial ini, Anda akan:

  • Menyesuaikan halaman kursus
  • Menambahkan office ke halaman instruktur
  • Menambahkan kursus ke halaman instruktur
  • Pembaruan DeleteConfirmed
  • Menambahkan lokasi dan kursus office ke halaman Buat

Prasyarat

Menyesuaikan halaman 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 Create metode dan Edit 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 (RetryLimitExceededException /* dex */)
    {
        //Log the error (uncomment dex variable name 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)
{
    if (id == null)
    {
        return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
    }
    Course course = db.Courses.Find(id);
    if (course == null)
    {
        return HttpNotFound();
    }
    PopulateDepartmentsDropDownList(course.DepartmentID);
    return View(course);
}

[HttpPost, ActionName("Edit")]
[ValidateAntiForgeryToken]
public ActionResult EditPost(int? id)
{
    if (id == null)
    {
        return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
    }
    var courseToUpdate = db.Courses.Find(id);
    if (TryUpdateModel(courseToUpdate, "",
       new string[] { "Title", "Credits", "DepartmentID" }))
    {
        try
        {
            db.SaveChanges();

            return RedirectToAction("Index");
        }
        catch (RetryLimitExceededException /* dex */)
        {
            //Log the error (uncomment dex variable name 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(courseToUpdate.DepartmentID);
    return View(courseToUpdate);
}

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

Tambahkan pernyataan berikut using di awal file:

using System.Data.Entity.Infrastructure;

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 ke pembantu DropDownList, dan pembantu kemudian tahu untuk melihat ViewBag objek untuk bernama SelectList DepartmentID.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)
{
    if (id == null)
    {
        return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
    }
    Course course = db.Courses.Find(id);
    if (course == null)
    {
        return HttpNotFound();
    }
    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 (RetryLimitExceededException /* dex */)
{
    //Log the error (uncomment dex variable name 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.

Tampilan Kursus sudah di-scaffold dengan daftar drop-down untuk bidang departemen, tetapi Anda tidak ingin keterangan DepartmentID untuk bidang ini, jadi buat perubahan yang disorot berikut ke file Views\Course\Create.cshtml untuk mengubah keterangan.

@model ContosoUniversity.Models.Course

@{
    ViewBag.Title = "Create";
}

<h2>Create</h2>

@using (Html.BeginForm()) 
{
    @Html.AntiForgeryToken()
    
    <div class="form-horizontal">
        <h4>Course</h4>
        <hr />
        @Html.ValidationSummary(true)

        <div class="form-group">
            @Html.LabelFor(model => model.CourseID, new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.CourseID)
                @Html.ValidationMessageFor(model => model.CourseID)
            </div>
        </div>

        <div class="form-group">
            @Html.LabelFor(model => model.Title, new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.Title)
                @Html.ValidationMessageFor(model => model.Title)
            </div>
        </div>

        <div class="form-group">
            @Html.LabelFor(model => model.Credits, new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.Credits)
                @Html.ValidationMessageFor(model => model.Credits)
            </div>
        </div>

        <div class="form-group">
            <label class="control-label col-md-2" for="DepartmentID">Department</label>
            <div class="col-md-10">
                @Html.DropDownList("DepartmentID", String.Empty)
                @Html.ValidationMessageFor(model => model.DepartmentID)
            </div>
        </div>

        <div class="form-group">
            <div class="col-md-offset-2 col-md-10">
                <input type="submit" value="Create" class="btn btn-default" />
            </div>
        </div>
    </div>
}

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

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

Buat perubahan yang sama di Views\Course\Edit.cshtml.

Biasanya perancah tidak membuat perancah kunci primer karena nilai kunci dihasilkan oleh database dan tidak dapat diubah dan bukan nilai yang bermakna untuk ditampilkan kepada pengguna. Untuk Entitas kursus perancah memang menyertakan kotak teks untuk CourseID bidang karena memahami bahwa DatabaseGeneratedOption.None atribut berarti pengguna harus dapat memasukkan nilai kunci utama. Tetapi tidak mengerti bahwa karena angkanya bermakna Anda ingin melihatnya di tampilan lain, jadi Anda perlu menambahkannya secara manual.

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

<div class="form-group">
    @Html.LabelFor(model => model.CourseID, new { @class = "control-label col-md-2" })
    <div class="col-md-10">
        @Html.DisplayFor(model => model.CourseID)
    </div>
</div>

Sudah ada bidang tersembunyi (Html.HiddenFor pembantu) untuk nomor kursus dalam tampilan Edit. Menambahkan pembantu Html.LabelFor tidak menghilangkan kebutuhan akan bidang tersembunyi karena tidak menyebabkan nomor kursus disertakan dalam data yang diposting saat pengguna mengklik Simpan di halaman Edit.

Di Views\Course\Delete.cshtml dan Views\Course\Details.cshtml, ubah keterangan nama departemen dari "Name" menjadi "Department" dan tambahkan bidang nomor kursus sebelum bidang Judul .

<dt>
    Department
</dt>

<dd>
    @Html.DisplayFor(model => model.Department.Name)
</dd>

<dt>
    @Html.DisplayNameFor(model => model.CourseID)
</dt>

<dd>
    @Html.DisplayFor(model => model.CourseID)
</dd>

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

Nilai Pengaturan
Number Masukkan 1000.
Judul Masukkan Aljabar.
Kredit Masukkan 4.
Departemen Pilih Matematika.

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.

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

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

Menambahkan office ke halaman 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

{
    if (id == null)
    {
        return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
    }
    Instructor instructor = db.Instructors.Find(id);
    if (instructor == null)
    {
        return HttpNotFound();
    }
    ViewBag.ID = new SelectList(db.OfficeAssignments, "InstructorID", "Location", instructor.ID);
    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)
{
    if (id == null)
    {
        return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
    }
    Instructor instructor = db.Instructors
        .Include(i => i.OfficeAssignment)
        .Where(i => i.ID == id)
        .Single();
    if (instructor == null)
    {
        return HttpNotFound();
    }
    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, ActionName("Edit")]
[ValidateAntiForgeryToken]
public ActionResult EditPost(int? id)
{
    if (id == null)
    {
        return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
    }
    var instructorToUpdate = db.Instructors
       .Include(i => i.OfficeAssignment)
       .Where(i => i.ID == id)
       .Single();

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

          db.SaveChanges();

          return RedirectToAction("Index");
       }
       catch (RetryLimitExceededException /* dex */)
      {
         //Log the error (uncomment dex variable name 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.");
      }
   }
   return View(instructorToUpdate);
}

Referensi untuk memerlukan using pernyataan; untuk menambahkannya - arahkan mouse Anda ke RetryLimitExceededException atas RetryLimitExceededException. Pesan berikut muncul:  Coba lagi pesan pengecualian

Pilih Tampilkan potensi perbaikan, lalu gunakan System.Data.Entity.Infrastructure

Mengatasi pengecualian Coba Lagi

Kode melakukan hal berikut:

  • Mengubah nama metode menjadi EditPost karena tanda tangan sekarang sama dengan HttpGet metode ( ActionName atribut menentukan bahwa /Edit/ URL masih digunakan).

  • 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 mencantumkan properti yang ingin Anda sertakan. 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="form-group">
    @Html.LabelFor(model => model.OfficeAssignment.Location, new { @class = "control-label col-md-2" })
    <div class="col-md-10">
        @Html.EditorFor(model => model.OfficeAssignment.Location)
        @Html.ValidationMessageFor(model => model.OfficeAssignment.Location)
    </div>
</div>

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

Menambahkan kursus ke halaman instruktur

Instruktur dapat mengajarkan sejumlah kursus. Sekarang Anda akan menyempurnakan halaman Edit Instruktur dengan menambahkan kemampuan untuk mengubah penetapan kursus menggunakan sekelompok kotak centang.

Hubungan antara Course entitas dan Instructor adalah banyak-ke-banyak, yang berarti Anda tidak memiliki akses langsung ke properti kunci asing yang berada dalam tabel gabungan. Sebagai gantinya, Anda 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)
{
    if (id == null)
    {
        return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
    }
    Instructor instructor = db.Instructors
        .Include(i => i.OfficeAssignment)
        .Include(i => i.Courses)
        .Where(i => i.ID == id)
        .Single();
    if (instructor == null)
    {
        return HttpNotFound();
    }
    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. EditPost 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, string[] selectedCourses)
{
    if (id == null)
    {
        return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
    }
    var instructorToUpdate = db.Instructors
       .Include(i => i.OfficeAssignment)
       .Include(i => i.Courses)
       .Where(i => i.ID == 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.SaveChanges();

            return RedirectToAction("Index");
        }
        catch (RetryLimitExceededException /* dex */)
        {
            //Log the error (uncomment dex variable name 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);
         }
      }
   }
}

Tanda tangan metode sekarang berbeda dari HttpGet Edit metode , sehingga nama metode berubah dari EditPost kembali ke Edit.

Karena tampilan tidak memiliki kumpulan Course entitas, pengikat model tidak dapat memperbarui Courses properti navigasi secara otomatis. Alih-alih menggunakan pengikat model untuk memperbarui Courses properti navigasi, 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 eksplisit 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 berikut segera setelah div elemen untuk OfficeAssignment bidang dan sebelum div elemen untuk tombol Simpan :

<div class="form-group">
    <div class="col-md-offset-2 col-md-10">
        <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>
</div>

Setelah Anda menempelkan kode, jika hentian baris dan indentasi tidak terlihat seperti yang mereka lakukan di sini, perbaiki semuanya secara manual sehingga terlihat seperti apa yang Anda lihat di sini. Indentasi tidak harus sempurna, tetapi @</tr><tr>baris , , @:<td>@:</td>, dan @</tr> masing-masing harus berada di satu baris seperti yang ditunjukkan atau Anda akan mendapatkan kesalahan runtime.

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>Last Name</th> 
    <th>First Name</th> 
    <th>Hire Date</th> 
    <th>Office</th>
    <th>Courses</th>
    <th></th> 
</tr>

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

<td>
    @if (item.OfficeAssignment != null)
    {
        @item.OfficeAssignment.Location
    }
</td>
<td>
    @{
        foreach (var course in item.Courses)
        {
            @course.CourseID @:  @course.Title <br />
        }
    }
</td>
<td>
    @Html.ActionLink("Select", "Index", new { id = item.ID }) |
    @Html.ActionLink("Edit", "Edit", new { id = item.ID }) |
    @Html.ActionLink("Details", "Details", new { id = item.ID }) |
    @Html.ActionLink("Delete", "Delete", new { id = item.ID })
</td>

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

Klik Edit pada instruktur untuk melihat halaman Edit.

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

Catatan: Pendekatan yang diambil di sini 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.

Pembaruan DeleteConfirmed

Di InstructorController.cs, hapus DeleteConfirmed metode dan sisipkan kode berikut di tempatnya.

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

   db.Instructors.Remove(instructor);

    var department = db.Departments
        .Where(d => d.InstructorID == id)
        .SingleOrDefault();
    if (department != null)
    {
        department.InstructorID = null;
    }

   db.SaveChanges();
   return RedirectToAction("Index");
}

Kode ini membuat perubahan berikut:

  • Jika instruktur ditetapkan sebagai administrator departemen apa pun, menghapus penugasan instruktur dari departemen tersebut. Tanpa kode ini, Anda akan mendapatkan kesalahan integritas referensial jika Anda mencoba menghapus instruktur yang ditetapkan sebagai administrator untuk departemen.

Kode ini tidak menangani skenario satu instruktur yang ditetapkan sebagai administrator untuk beberapa departemen. Dalam tutorial terakhir, Anda akan menambahkan kode yang mencegah skenario tersebut terjadi.

Menambahkan lokasi dan kursus office ke halaman Buat

Di InstructorController.cs, hapus HttpGet metode dan HttpPost Create , lalu tambahkan kode berikut di tempatnya:

public ActionResult Create()
{
    var instructor = new Instructor();
    instructor.Courses = new List<Course>();
    PopulateAssignedCourseData(instructor);
    return View();
}

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create([Bind(Include = "LastName,FirstMidName,HireDate,OfficeAssignment" )]Instructor instructor, string[] selectedCourses)
{
    if (selectedCourses != null)
    {
        instructor.Courses = new List<Course>();
        foreach (var course in selectedCourses)
        {
            var courseToAdd = db.Courses.Find(int.Parse(course));
            instructor.Courses.Add(courseToAdd);
        }
    }
    if (ModelState.IsValid)
    {
        db.Instructors.Add(instructor);
        db.SaveChanges();
        return RedirectToAction("Index");
    }
    PopulateAssignedCourseData(instructor);
    return View(instructor);
}

Kode ini mirip dengan apa yang Anda lihat untuk metode Edit kecuali bahwa awalnya tidak ada kursus yang dipilih. Metode HttpGet Create memanggil PopulateAssignedCourseData metode bukan karena mungkin ada kursus yang dipilih tetapi untuk menyediakan koleksi kosong untuk foreach perulangan dalam tampilan (jika tidak, kode tampilan akan melemparkan pengecualian referensi null).

Metode HttpPost Create menambahkan setiap kursus yang dipilih ke properti navigasi Kursus sebelum kode templat yang memeriksa kesalahan validasi dan menambahkan instruktur baru ke database. Kursus ditambahkan bahkan jika ada kesalahan model sehingga ketika ada kesalahan model (misalnya, pengguna memasukkan tanggal yang tidak valid) sehingga ketika halaman diputar ulang dengan pesan kesalahan, pilihan kursus apa pun yang dibuat dipulihkan secara otomatis.

Perhatikan bahwa untuk dapat menambahkan kursus ke Courses properti navigasi, Anda harus menginisialisasi properti sebagai koleksi kosong:

instructor.Courses = new List<Course>();

Sebagai alternatif untuk melakukan ini dalam kode pengontrol, Anda dapat melakukannya dalam model Instruktur dengan mengubah getter properti untuk membuat koleksi secara otomatis jika tidak ada, seperti yang ditunjukkan dalam contoh berikut:

private ICollection<Course> _courses;
public virtual ICollection<Course> Courses 
{ 
    get
    {
        return _courses ?? (_courses = new List<Course>());
    }
    set
    {
        _courses = value;
    } 
}

Jika Anda mengubah properti dengan Courses cara ini, Anda dapat menghapus kode inisialisasi properti eksplisit di pengontrol.

Di Views\Instructor\Create.cshtml, tambahkan kotak teks lokasi office dan kotak centang kursus setelah bidang tanggal sewa dan sebelum tombol Kirim .

<div class="form-group">
    @Html.LabelFor(model => model.OfficeAssignment.Location, new { @class = "control-label col-md-2" })
    <div class="col-md-10">
        @Html.EditorFor(model => model.OfficeAssignment.Location)
        @Html.ValidationMessageFor(model => model.OfficeAssignment.Location)
    </div>
</div>

<div class="form-group">
    <div class="col-md-offset-2 col-md-10">
        <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>
</div>

Setelah Anda menempelkan kode, perbaiki hentian baris dan indentasi seperti yang Anda lakukan sebelumnya untuk halaman Edit.

Jalankan halaman Buat dan tambahkan instruktur.

Menangani transaksi

Seperti yang dijelaskan dalam tutorial Fungsionalitas CRUD Dasar, secara default Kerangka Kerja Entitas secara implisit menerapkan transaksi. Untuk skenario di mana Anda memerlukan lebih banyak kontrol -- misalnya, jika Anda ingin menyertakan operasi yang dilakukan di luar Kerangka Kerja Entitas dalam transaksi -- lihat Bekerja dengan Transaksi di MSDN.

Mendapatkan kode

Unduh Proyek yang Selesai

Sumber Daya Tambahan:

Tautan ke sumber daya Kerangka Kerja Entitas lainnya dapat ditemukan di ASP.NET Akses Data - Sumber Daya yang Direkomendasikan.

Langkah selanjutnya

Di tutorial ini, Anda akan:

  • Halaman kursus yang dikustomisasi
  • Menambahkan office ke halaman instruktur
  • Menambahkan kursus ke halaman instruktur
  • DeleteConfirmed yang Diperbarui
  • Menambahkan lokasi dan kursus office ke halaman Buat

Lanjutkan ke artikel berikutnya untuk mempelajari cara menerapkan model pemrograman asinkron.