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.
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:
Pilih Tampilkan potensi perbaikan, lalu gunakan System.Data.Entity.Infrastructure
Kode melakukan hal berikut:
Mengubah nama metode menjadi
EditPost
karena tanda tangan sekarang sama denganHttpGet
metode (ActionName
atribut menentukan bahwa /Edit/ URL masih digunakan).Mendapatkan entitas saat ini
Instructor
dari database menggunakan pemuatan bersemangat untukOfficeAssignment
properti navigasi. Ini sama dengan apa yang Anda lakukan dalamHttpGet
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 dalamOfficeAssignment
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
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.
Saran dan Komentar
https://aka.ms/ContentUserFeedback.
Segera hadir: Sepanjang tahun 2024 kami akan menghentikan penggunaan GitHub Issues sebagai mekanisme umpan balik untuk konten dan menggantinya dengan sistem umpan balik baru. Untuk mengetahui informasi selengkapnya, lihat:Kirim dan lihat umpan balik untuk