Tutorial: Menerapkan Fungsionalitas CRUD - ASP.NET MVC dengan EF Core
Dalam tutorial sebelumnya, Anda membuat aplikasi MVC yang menyimpan dan menampilkan data menggunakan Kerangka Kerja Entitas dan SQL Server LocalDB. Dalam tutorial ini, Anda akan meninjau dan menyesuaikan kode CRUD (buat, baca, perbarui, hapus) yang dibuat perancah MVC secara otomatis untuk Anda dalam pengontrol dan tampilan.
Catatan
Ini adalah praktik umum untuk menerapkan pola repositori untuk membuat lapisan abstraksi antara pengontrol Anda dan lapisan akses data. Untuk menjaga tutorial ini tetap sederhana dan berfokus pada pengajaran cara menggunakan Kerangka Kerja Entitas itu sendiri, mereka tidak menggunakan repositori. Untuk informasi tentang repositori dengan EF, lihat tutorial terakhir dalam seri ini.
Di tutorial ini, Anda akan:
- Mengkustomisasi halaman Detail
- Memperbarui halaman Buat
- Memperbarui halaman Edit
- Memperbarui halaman Hapus
- Menutup koneksi database
Prasyarat
Mengkustomisasi halaman Detail
Kode perancah untuk halaman Indeks Siswa meninggalkan Enrollments
properti , karena properti tersebut menyimpan koleksi. Di halaman Detail , Anda akan menampilkan konten koleksi dalam tabel HTML.
Dalam Controllers/StudentsController.cs
, metode tindakan untuk tampilan Detail menggunakan FirstOrDefaultAsync
metode untuk mengambil satu Student
entitas. Tambahkan kode yang memanggil Include
. ThenInclude
, dan AsNoTracking
metode, seperti yang ditunjukkan dalam kode yang disorot berikut.
public async Task<IActionResult> Details(int? id)
{
if (id == null)
{
return NotFound();
}
var student = await _context.Students
.Include(s => s.Enrollments)
.ThenInclude(e => e.Course)
.AsNoTracking()
.FirstOrDefaultAsync(m => m.ID == id);
if (student == null)
{
return NotFound();
}
return View(student);
}
Metode Include
dan ThenInclude
menyebabkan konteks memuat Student.Enrollments
properti navigasi, dan dalam setiap pendaftaran Enrollment.Course
properti navigasi. Anda akan mempelajari selengkapnya tentang metode ini dalam tutorial membaca data terkait.
Metode ini AsNoTracking
meningkatkan performa dalam skenario di mana entitas yang dikembalikan tidak akan diperbarui dalam masa pakai konteks saat ini. Anda akan mempelajari lebih AsNoTracking
lanjut di akhir tutorial ini.
Merutekan data
Nilai kunci yang diteruskan ke Details
metode berasal dari data rute. Data rute adalah data yang ditemukan pengikat model di segmen URL. Misalnya, rute default menentukan segmen pengontrol, tindakan, dan id:
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
});
Dalam URL berikut, rute default memetakan Instruktur sebagai pengontrol, Indeks sebagai tindakan, dan 1 sebagai id; ini adalah nilai data rute.
http://localhost:1230/Instructor/Index/1?courseID=2021
Bagian terakhir dari URL ("?courseID=2021") adalah nilai string kueri. Pengikat model juga akan meneruskan nilai ID ke Index
parameter metode id
jika Anda meneruskannya sebagai nilai string kueri:
http://localhost:1230/Instructor/Index?id=1&CourseID=2021
Di halaman Indeks, URL hyperlink dibuat oleh pernyataan pembantu Razor tag dalam tampilan. Dalam kode berikut Razor , id
parameter cocok dengan rute default, sehingga id
ditambahkan ke data rute.
<a asp-action="Edit" asp-route-id="@item.ID">Edit</a>
Ini menghasilkan HTML berikut ketika item.ID
adalah 6:
<a href="/Students/Edit/6">Edit</a>
Dalam kode berikut Razor , studentID
tidak cocok dengan parameter dalam rute default, sehingga ditambahkan sebagai string kueri.
<a asp-action="Edit" asp-route-studentID="@item.ID">Edit</a>
Ini menghasilkan HTML berikut ketika item.ID
adalah 6:
<a href="/Students/Edit?studentID=6">Edit</a>
Untuk informasi selengkapnya tentang pembantu tag, lihat Pembantu Tag di ASP.NET Core.
Menambahkan pendaftaran ke tampilan Detail
Buka Views/Students/Details.cshtml
. Setiap bidang ditampilkan menggunakan DisplayNameFor
dan DisplayFor
pembantu, seperti yang ditunjukkan dalam contoh berikut:
<dt class="col-sm-2">
@Html.DisplayNameFor(model => model.LastName)
</dt>
<dd class="col-sm-10">
@Html.DisplayFor(model => model.LastName)
</dd>
Setelah bidang terakhir dan segera sebelum tag penutup </dl>
, tambahkan kode berikut untuk menampilkan daftar pendaftaran:
<dt class="col-sm-2">
@Html.DisplayNameFor(model => model.Enrollments)
</dt>
<dd class="col-sm-10">
<table class="table">
<tr>
<th>Course Title</th>
<th>Grade</th>
</tr>
@foreach (var item in Model.Enrollments)
{
<tr>
<td>
@Html.DisplayFor(modelItem => item.Course.Title)
</td>
<td>
@Html.DisplayFor(modelItem => item.Grade)
</td>
</tr>
}
</table>
</dd>
Jika indentasi kode salah setelah Anda menempelkan kode, tekan CTRL-K-D untuk memperbaikinya.
Kode ini mengulangi entitas di Enrollments
properti navigasi. Untuk setiap pendaftaran, ini menampilkan judul kursus dan nilai. Judul kursus diambil dari entitas Kursus yang disimpan di Course
properti navigasi entitas Pendaftaran.
Jalankan aplikasi, pilih tab Siswa , dan klik tautan Detail untuk siswa. Anda melihat daftar kursus dan nilai untuk siswa yang dipilih:
Memperbarui halaman Buat
Dalam StudentsController.cs
, ubah metode HttpPost Create
dengan menambahkan blok try-catch dan menghapus ID dari Bind
atribut .
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create(
[Bind("EnrollmentDate,FirstMidName,LastName")] Student student)
{
try
{
if (ModelState.IsValid)
{
_context.Add(student);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
}
catch (DbUpdateException /* ex */)
{
//Log the error (uncomment ex variable name and write a log.
ModelState.AddModelError("", "Unable to save changes. " +
"Try again, and if the problem persists " +
"see your system administrator.");
}
return View(student);
}
Kode ini menambahkan entitas Siswa yang dibuat oleh ASP.NET pengikat model Core MVC ke kumpulan entitas Siswa lalu menyimpan perubahan ke database. (Pengikat model mengacu pada fungsionalitas ASP.NET Core MVC yang memudahkan Anda untuk bekerja dengan data yang dikirimkan oleh formulir; pengikat model mengonversi nilai formulir yang diposting ke jenis CLR dan meneruskannya ke metode tindakan dalam parameter. Dalam hal ini, pengikat model membuat instans entitas Siswa untuk Anda menggunakan nilai properti dari koleksi Formulir.)
Anda menghapus ID
dari Bind
atribut karena ID adalah nilai kunci utama yang akan diatur SQL Server secara otomatis saat baris disisipkan. Input dari pengguna tidak mengatur nilai ID.
Bind
Selain atribut , blok try-catch adalah satu-satunya perubahan yang Telah Anda lakukan pada kode perancah. Jika pengecualian yang berasal dari DbUpdateException
tertangkap saat perubahan sedang disimpan, pesan kesalahan umum ditampilkan. DbUpdateException
pengecualian terkadang disebabkan oleh sesuatu di luar aplikasi daripada kesalahan pemrograman, sehingga pengguna disarankan untuk mencoba lagi. Meskipun tidak diimplementasikan dalam sampel ini, aplikasi kualitas produksi akan mencatat pengecualian. Untuk informasi selengkapnya, lihat bagian Log untuk wawasan di Pemantauan dan Telemetri (Membangun Aplikasi Cloud Dunia Nyata dengan Azure).
Atribut ini ValidateAntiForgeryToken
membantu mencegah serangan pemalsuan permintaan lintas situs (CSRF). Token secara otomatis dimasukkan ke dalam tampilan oleh FormTagHelper dan disertakan ketika formulir dikirimkan oleh pengguna. Token divalidasi oleh ValidateAntiForgeryToken
atribut . Untuk informasi selengkapnya, lihat Mencegah serangan Pemalsuan Permintaan Antar Situs (XSRF/CSRF) di ASP.NET Core.
Catatan keamanan tentang overposting
Atribut Bind
yang disertakan dalam kode perancah pada Create
metode adalah salah satu cara untuk melindungi dari overposting dalam membuat skenario. Misalnya, entitas Siswa menyertakan Secret
properti yang tidak ingin Anda atur halaman web ini.
public class Student
{
public int ID { get; set; }
public string LastName { get; set; }
public string FirstMidName { get; set; }
public DateTime EnrollmentDate { get; set; }
public string Secret { get; set; }
}
Bahkan jika Anda tidak memiliki Secret
bidang di halaman web, peretas dapat menggunakan alat seperti Fiddler, atau menulis beberapa JavaScript, untuk memposting Secret
nilai formulir. Bind
Tanpa atribut yang membatasi bidang yang digunakan pengikat model saat membuat instans Siswa, pengikat model akan mengambil Secret
nilai formulir tersebut dan menggunakannya untuk membuat instans entitas Siswa. Kemudian nilai apa pun yang ditentukan peretas untuk Secret
bidang formulir akan diperbarui dalam database Anda. Gambar berikut menunjukkan alat Fiddler yang menambahkan Secret
bidang (dengan nilai "OverPost") ke nilai formulir yang diposting.
Nilai "OverPost" kemudian akan berhasil ditambahkan ke Secret
properti baris yang disisipkan, meskipun Anda tidak pernah bermaksud agar halaman web dapat mengatur properti tersebut.
Anda dapat mencegah overposting dalam skenario edit dengan membaca entitas dari database terlebih dahulu lalu memanggil TryUpdateModel
, meneruskan daftar properti eksplisit yang diizinkan. Itulah metode yang digunakan dalam tutorial ini.
Cara alternatif untuk mencegah overposting yang lebih disukai oleh banyak pengembang adalah dengan menggunakan model tampilan daripada kelas entitas dengan pengikatan model. Sertakan hanya properti yang ingin Anda perbarui dalam model tampilan. Setelah pengikat model MVC selesai, salin properti model tampilan ke instans entitas, secara opsional menggunakan alat seperti AutoMapper. Gunakan _context.Entry
pada instans entitas untuk mengatur statusnya ke Unchanged
, lalu atur Property("PropertyName").IsModified
ke true pada setiap properti entitas yang disertakan dalam model tampilan. Metode ini berfungsi dalam skenario edit dan buat.
Menguji halaman Buat
Kode dalam Views/Students/Create.cshtml
menggunakan pembantu label
tag , input
, dan span
(untuk pesan validasi) untuk setiap bidang.
Jalankan aplikasi, pilih tab Siswa , dan klik Buat Baru.
Masukkan nama dan tanggal. Coba masukkan tanggal yang tidak valid jika browser memungkinkan Anda melakukannya. (Beberapa browser memaksa Anda menggunakan pemilih tanggal.) Lalu klik Buat untuk melihat pesan kesalahan.
Ini adalah validasi sisi server yang Anda dapatkan secara default; dalam tutorial selanjutnya, Anda akan melihat cara menambahkan atribut yang akan menghasilkan kode untuk validasi sisi klien juga. Kode yang disorot berikut menunjukkan pemeriksaan validasi model dalam Create
metode .
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create(
[Bind("EnrollmentDate,FirstMidName,LastName")] Student student)
{
try
{
if (ModelState.IsValid)
{
_context.Add(student);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
}
catch (DbUpdateException /* ex */)
{
//Log the error (uncomment ex variable name and write a log.
ModelState.AddModelError("", "Unable to save changes. " +
"Try again, and if the problem persists " +
"see your system administrator.");
}
return View(student);
}
Ubah tanggal menjadi nilai yang valid dan klik Buat untuk melihat siswa baru muncul di halaman Indeks .
Memperbarui halaman Edit
Dalam StudentController.cs
, metode HttpGet Edit
(yang tanpa HttpPost
atribut) menggunakan FirstOrDefaultAsync
metode untuk mengambil entitas Siswa yang dipilih, seperti yang Anda lihat dalam Details
metode . Anda tidak perlu mengubah metode ini.
Kode Edit HttpPost yang Direkomendasikan: Membaca dan memperbarui
Ganti metode tindakan HttpPost Edit dengan kode berikut.
[HttpPost, ActionName("Edit")]
[ValidateAntiForgeryToken]
public async Task<IActionResult> EditPost(int? id)
{
if (id == null)
{
return NotFound();
}
var studentToUpdate = await _context.Students.FirstOrDefaultAsync(s => s.ID == id);
if (await TryUpdateModelAsync<Student>(
studentToUpdate,
"",
s => s.FirstMidName, s => s.LastName, s => s.EnrollmentDate))
{
try
{
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
catch (DbUpdateException /* ex */)
{
//Log the error (uncomment ex variable name and write a log.)
ModelState.AddModelError("", "Unable to save changes. " +
"Try again, and if the problem persists, " +
"see your system administrator.");
}
}
return View(studentToUpdate);
}
Perubahan ini menerapkan praktik terbaik keamanan untuk mencegah overposting. Perancah menghasilkan atribut dan menambahkan entitas yang Bind
dibuat oleh pengikat model ke entitas yang Modified
ditetapkan dengan bendera. Kode tersebut tidak disarankan untuk banyak skenario karena Bind
atribut menghapus data yang sudah ada sebelumnya di bidang yang tidak tercantum dalam Include
parameter.
Kode baru membaca entitas yang ada dan panggilan TryUpdateModel
untuk memperbarui bidang di entitas yang diambil berdasarkan input pengguna dalam data formulir yang diposting. Pelacakan perubahan otomatis Entity Framework mengatur Modified
bendera pada bidang yang diubah oleh input formulir. Ketika metode dipanggil SaveChanges
, Kerangka Kerja Entitas membuat pernyataan SQL untuk memperbarui baris database. Konflik konkurensi diabaikan, dan hanya kolom tabel yang diperbarui oleh pengguna yang diperbarui dalam database. (Tutorial selanjutnya menunjukkan cara menangani konflik konkurensi.)
Sebagai praktik terbaik untuk mencegah overposting, bidang yang ingin Anda perbarui oleh halaman Edit dideklarasikan dalam TryUpdateModel
parameter. (String kosong yang mendahului daftar bidang dalam daftar parameter adalah untuk awalan yang akan digunakan dengan nama bidang formulir.) Saat ini tidak ada bidang tambahan yang Anda lindungi, tetapi mencantumkan bidang yang Anda inginkan agar pengikat pengikat model memastikan bahwa jika Anda menambahkan bidang ke model data di masa mendatang, bidang tersebut secara otomatis dilindungi hingga Anda secara eksplisit menambahkannya di sini.
Akibat perubahan ini, tanda tangan metode metode HttpPost Edit
sama dengan metode HttpGet Edit
; oleh karena itu Anda telah mengganti nama metode EditPost
.
Kode Edit HttpPost alternatif: Membuat dan melampirkan
Kode edit HttpPost yang direkomendasikan memastikan bahwa hanya kolom yang diubah yang diperbarui dan mempertahankan data dalam properti yang tidak ingin Anda sertakan untuk pengikatan model. Namun, pendekatan baca-pertama memerlukan pembacaan database tambahan, dan dapat menghasilkan kode yang lebih kompleks untuk menangani konflik konkurensi. Alternatifnya adalah melampirkan entitas yang dibuat oleh pengikat model ke konteks EF dan menandainya sebagai dimodifikasi. (Jangan perbarui proyek Anda dengan kode ini, itu hanya ditampilkan untuk mengilustrasikan pendekatan opsional.)
public async Task<IActionResult> Edit(int id, [Bind("ID,EnrollmentDate,FirstMidName,LastName")] Student student)
{
if (id != student.ID)
{
return NotFound();
}
if (ModelState.IsValid)
{
try
{
_context.Update(student);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
catch (DbUpdateException /* ex */)
{
//Log the error (uncomment ex variable name and write a log.)
ModelState.AddModelError("", "Unable to save changes. " +
"Try again, and if the problem persists, " +
"see your system administrator.");
}
}
return View(student);
}
Anda dapat menggunakan pendekatan ini saat UI halaman web menyertakan semua bidang di entitas dan dapat memperbarui salah satunya.
Kode perancah menggunakan pendekatan create-and-attach tetapi hanya menangkap DbUpdateConcurrencyException
pengecualian dan mengembalikan kode kesalahan 404. Contoh yang ditampilkan menangkap pengecualian pembaruan database apa pun dan menampilkan pesan kesalahan.
Status Entitas
Konteks database melacak apakah entitas dalam memori sinkron dengan baris yang sesuai dalam database, dan informasi ini menentukan apa yang terjadi saat Anda memanggil SaveChanges
metode . Misalnya, ketika Anda meneruskan entitas baru ke Add
metode , status entitas tersebut diatur ke Added
. Kemudian saat Anda memanggil metode , SaveChanges
konteks database mengeluarkan perintah SQL INSERT.
Entitas mungkin berada di salah satu status berikut:
Added
. Entitas belum ada di database. Metode mengeluarkanSaveChanges
pernyataan INSERT.Unchanged
. Tidak ada yang perlu dilakukan dengan entitas ini denganSaveChanges
metode . Saat Anda membaca entitas dari database, entitas dimulai dengan status ini.Modified
. Beberapa atau semua nilai properti entitas telah dimodifikasi. Metode iniSaveChanges
mengeluarkan pernyataan UPDATE.Deleted
. Entitas telah ditandai untuk dihapus. Metode mengeluarkanSaveChanges
pernyataan DELETE.Detached
. Entitas tidak dilacak oleh konteks database.
Dalam aplikasi desktop, perubahan status biasanya diatur secara otomatis. Anda membaca entitas dan membuat perubahan pada beberapa nilai propertinya. Ini menyebabkan status entitasnya secara otomatis diubah menjadi Modified
. Kemudian saat Anda memanggil SaveChanges
, Kerangka Kerja Entitas menghasilkan pernyataan PEMBARUAN SQL yang hanya memperbarui properti aktual yang Anda ubah.
Di aplikasi web, DbContext
yang awalnya membaca entitas dan menampilkan datanya untuk diedit dibuang setelah halaman dirender. Ketika metode tindakan HttpPost Edit
dipanggil, permintaan web baru dibuat dan Anda memiliki instans baru dari DbContext
. Jika Anda membaca ulang entitas dalam konteks baru tersebut, Anda mensimulasikan pemrosesan desktop.
Tetapi jika Anda tidak ingin melakukan operasi baca tambahan, Anda harus menggunakan objek entitas yang dibuat oleh pengikat model. Cara paling sederhana untuk melakukan ini adalah dengan mengatur status entitas ke Dimodifikasi seperti yang dilakukan dalam kode HttpPost Edit alternatif yang ditunjukkan sebelumnya. Kemudian saat Anda memanggil SaveChanges
, Kerangka Kerja Entitas memperbarui semua kolom baris database, karena konteks tidak memiliki cara untuk mengetahui properti mana yang Anda ubah.
Jika Anda ingin menghindari pendekatan baca-pertama, tetapi Anda juga ingin pernyataan PEMBARUAN SQL memperbarui hanya bidang yang benar-benar diubah pengguna, kodenya lebih kompleks. Anda harus menyimpan nilai asli dalam beberapa cara (seperti dengan menggunakan bidang tersembunyi) sehingga tersedia saat metode HttpPost Edit
dipanggil. Kemudian Anda dapat membuat entitas Siswa menggunakan nilai asli, memanggil Attach
metode dengan versi asli entitas tersebut, memperbarui nilai entitas ke nilai baru, lalu memanggil SaveChanges
.
Menguji halaman Edit
Jalankan aplikasi, pilih tab Siswa , lalu klik Edit hyperlink.
Ubah beberapa data dan klik Simpan. Halaman Indeks terbuka dan Anda melihat data yang diubah.
Memperbarui halaman Hapus
Dalam StudentController.cs
, kode templat untuk metode HttpGet Delete
menggunakan FirstOrDefaultAsync
metode untuk mengambil entitas Siswa yang dipilih, seperti yang Anda lihat dalam metode Detail dan Edit. Namun, untuk menerapkan pesan kesalahan kustom saat panggilan gagal SaveChanges
, Anda akan menambahkan beberapa fungsionalitas ke metode ini dan tampilan yang sesuai.
Seperti yang Anda lihat untuk memperbarui dan membuat operasi, operasi penghapusan memerlukan dua metode tindakan. Metode yang dipanggil sebagai respons terhadap permintaan GET menampilkan tampilan yang memberi pengguna kesempatan untuk menyetujui atau membatalkan operasi penghapusan. Jika pengguna menyetujuinya, permintaan POST dibuat. Ketika itu terjadi, metode HttpPost Delete
dipanggil dan kemudian metode itu benar-benar melakukan operasi penghapusan.
Anda akan menambahkan blok try-catch ke metode HttpPost Delete
untuk menangani kesalahan apa pun yang mungkin terjadi saat database diperbarui. Jika terjadi kesalahan, metode Hapus HttpPost memanggil metode HttpGet Delete, meneruskannya parameter yang menunjukkan bahwa kesalahan telah terjadi. Metode Hapus HttpGet kemudian memutar ulang halaman konfirmasi bersama dengan pesan kesalahan, memberi pengguna kesempatan untuk membatalkan atau mencoba lagi.
Ganti metode tindakan HttpGet Delete
dengan kode berikut, yang mengelola pelaporan kesalahan.
public async Task<IActionResult> Delete(int? id, bool? saveChangesError = false)
{
if (id == null)
{
return NotFound();
}
var student = await _context.Students
.AsNoTracking()
.FirstOrDefaultAsync(m => m.ID == id);
if (student == null)
{
return NotFound();
}
if (saveChangesError.GetValueOrDefault())
{
ViewData["ErrorMessage"] =
"Delete failed. Try again, and if the problem persists " +
"see your system administrator.";
}
return View(student);
}
Kode ini menerima parameter opsional yang menunjukkan apakah metode dipanggil setelah kegagalan untuk menyimpan perubahan. Parameter ini salah ketika metode HttpGet Delete
dipanggil tanpa kegagalan sebelumnya. Ketika dipanggil oleh metode HttpPost Delete
sebagai respons terhadap kesalahan pembaruan database, parameter tersebut benar dan pesan kesalahan diteruskan ke tampilan.
Pendekatan baca-pertama untuk Hapus HttpPost
Ganti metode tindakan HttpPost Delete
(bernama DeleteConfirmed
) dengan kode berikut, yang melakukan operasi penghapusan aktual dan menangkap kesalahan pembaruan database apa pun.
[HttpPost, ActionName("Delete")]
[ValidateAntiForgeryToken]
public async Task<IActionResult> DeleteConfirmed(int id)
{
var student = await _context.Students.FindAsync(id);
if (student == null)
{
return RedirectToAction(nameof(Index));
}
try
{
_context.Students.Remove(student);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
catch (DbUpdateException /* ex */)
{
//Log the error (uncomment ex variable name and write a log.)
return RedirectToAction(nameof(Delete), new { id = id, saveChangesError = true });
}
}
Kode ini mengambil entitas yang dipilih, lalu memanggil Remove
metode untuk mengatur status entitas ke Deleted
. Ketika SaveChanges
dipanggil, perintah SQL DELETE dihasilkan.
Pendekatan create-and-attach ke HttpPost Delete
Jika meningkatkan performa dalam aplikasi volume tinggi adalah prioritas, Anda dapat menghindari kueri SQL yang tidak perlu dengan membuat instans entitas Siswa hanya menggunakan nilai kunci utama lalu mengatur status entitas ke Deleted
. Itu saja yang dibutuhkan Entity Framework untuk menghapus entitas. (Jangan letakkan kode ini dalam proyek Anda; kode ini ada di sini hanya untuk menggambarkan alternatif.)
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> DeleteConfirmed(int id)
{
try
{
Student studentToDelete = new Student() { ID = id };
_context.Entry(studentToDelete).State = EntityState.Deleted;
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
catch (DbUpdateException /* ex */)
{
//Log the error (uncomment ex variable name and write a log.)
return RedirectToAction(nameof(Delete), new { id = id, saveChangesError = true });
}
}
Jika entitas memiliki data terkait yang juga harus dihapus, pastikan bahwa penghapusan kaskade dikonfigurasi dalam database. Dengan pendekatan penghapusan entitas ini, EF mungkin tidak menyadari ada entitas terkait yang akan dihapus.
Memperbarui tampilan Hapus
Di Views/Student/Delete.cshtml
, tambahkan pesan kesalahan antara judul h2 dan judul h3, seperti yang ditunjukkan dalam contoh berikut:
<h2>Delete</h2>
<p class="text-danger">@ViewData["ErrorMessage"]</p>
<h3>Are you sure you want to delete this?</h3>
Jalankan aplikasi, pilih tab Siswa , dan klik Hapus hyperlink:
Klik Hapus. Halaman Indeks ditampilkan tanpa siswa yang dihapus. (Anda akan melihat contoh kode penanganan kesalahan dalam tindakan dalam tutorial konkurensi.)
Menutup koneksi database
Untuk membebaskan sumber daya yang disimpan koneksi database, instans konteks harus dibuang sesegera mungkin ketika Anda selesai dengannya. Injeksi dependensi bawaan ASP.NET Core mengurus tugas tersebut untuk Anda.
Dalam Startup.cs
, Anda memanggil metode ekstensi AddDbContext untuk menyediakan DbContext
kelas dalam kontainer ASP.NET Core DI. Metode tersebut mengatur masa pakai layanan menjadi Scoped
secara default. Scoped
berarti masa pakai objek konteks bertepatan dengan waktu hidup permintaan web, dan Dispose
metode akan dipanggil secara otomatis di akhir permintaan web.
Menangani transaksi
Secara default, Entity Framework secara implisit mengimplementasikan transaksi. Dalam skenario di mana Anda membuat perubahan pada beberapa baris atau tabel lalu memanggil SaveChanges
, Kerangka Kerja Entitas secara otomatis memastikan bahwa semua perubahan Anda berhasil atau semuanya gagal. Jika beberapa perubahan dilakukan terlebih dahulu dan kemudian terjadi kesalahan, perubahan tersebut secara otomatis digulung balik. 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 Transaksi.
Kueri tanpa pelacakan
Saat konteks database mengambil baris tabel dan membuat objek entitas yang mewakilinya, secara default konteks tersebut melacak apakah entitas dalam memori sinkron dengan apa yang ada di database. Data dalam memori bertindak sebagai cache dan digunakan saat Anda memperbarui entitas. Penembolokan ini sering kali tidak perlu dalam aplikasi web karena instans konteks biasanya berumur pendek (yang baru dibuat dan dibuang untuk setiap permintaan) dan konteks yang membaca entitas biasanya dibuang sebelum entitas tersebut digunakan lagi.
Anda dapat menonaktifkan pelacakan objek entitas dalam memori dengan memanggil AsNoTracking
metode . Skenario umum di mana Anda mungkin ingin melakukannya termasuk yang berikut ini:
Selama masa pakai konteks, Anda tidak perlu memperbarui entitas apa pun, dan Anda tidak memerlukan EF untuk memuat properti navigasi secara otomatis dengan entitas yang diambil oleh kueri terpisah. Sering kali kondisi ini terpenuhi dalam metode tindakan HttpGet pengontrol.
Anda menjalankan kueri yang mengambil data dalam volume besar, dan hanya sebagian kecil data yang dikembalikan yang akan diperbarui. Mungkin lebih efisien untuk menonaktifkan pelacakan untuk kueri besar, dan menjalankan kueri nanti untuk beberapa entitas yang perlu diperbarui.
Anda ingin melampirkan entitas untuk memperbaruinya, tetapi sebelumnya Anda mengambil entitas yang sama untuk tujuan yang berbeda. Karena entitas sudah dilacak oleh konteks database, Anda tidak dapat melampirkan entitas yang ingin Anda ubah. Salah satu cara untuk menangani situasi ini adalah dengan memanggil
AsNoTracking
kueri sebelumnya.
Untuk informasi selengkapnya, lihat Pelacakan vs. Tanpa Pelacakan.
Mendapatkan kode
Unduh atau lihat aplikasi yang telah selesai.
Langkah berikutnya
Di tutorial ini, Anda akan:
- Mengkustomisasi halaman Detail
- Memperbarui halaman Buat
- Memperbarui halaman Edit
- Memperbarui halaman Hapus
- Koneksi database tertutup
Lanjutkan ke tutorial berikutnya untuk mempelajari cara memperluas fungsionalitas halaman Indeks dengan menambahkan pengurutan, pemfilteran, dan penomoran halaman.
ASP.NET Core