Memiliki dua kelas:
public class Parent
{
public int Id { get; set; }
public int ChildId { get; set; }
}
public class Child { ... }
Ketika menetapkan ChildId
untuk Parent
harus saya cek dulu jika ada di DB atau menunggu DB untuk melemparkan pengecualian?
Misalnya (menggunakan Entity Framework Core):
Perhatikan jenis-jenis cek ini SELURUH INTERNET, bahkan pada dokumen resmi Microsoft: https://docs.microsoft.com/en-us/aspnet/mvc/overview/getting-started/getting-started-with-ef-using- mvc / handling-concurrency-with-the-entitas-framework-in-an-asp-net-mvc-application #odifikasi-departemen-pengontrol tetapi ada penanganan pengecualian tambahan untukSaveChanges
juga, perhatikan bahwa maksud utama dari pemeriksaan ini adalah untuk mengembalikan pesan ramah dan status HTTP yang diketahui kepada pengguna API dan tidak sepenuhnya mengabaikan pengecualian basis data. Dan satu-satunya pengecualian tempat yang dibuang adalah di dalam SaveChanges
atau SaveChangesAsync
menelepon ... jadi tidak akan ada pengecualian saat Anda menelepon FindAsync
atau Any
. Jadi jika anak ada tetapi sudah dihapus sebelumnya SaveChangesAsync
maka pengecualian concurrency akan dibuang.
Saya melakukan ini karena fakta bahwa foreign key violation
pengecualian akan jauh lebih sulit untuk memformat untuk menampilkan "Anak dengan id {parent.ChildId} tidak dapat ditemukan."
public async Task<ActionResult<Parent>> CreateParent(Parent parent)
{
// is this code redundant?
// NOTE: its probably better to use Any isntead of FindAsync because FindAsync selects *, and Any selects 1
var child = await _db.Children.FindAsync(parent.ChildId);
if (child == null)
return NotFound($"Child with id {parent.ChildId} could not be found.");
_db.Parents.Add(parent);
await _db.SaveChangesAsync();
return parent;
}
melawan:
public async Task<ActionResult<Parent>> CreateParent(Parent parent)
{
_db.Parents.Add(parent);
await _db.SaveChangesAsync(); // handle exception somewhere globally when child with the specified id doesn't exist...
return parent;
}
Contoh kedua di Postgres akan menampilkan 23503 foreign_key_violation
kesalahan: https://www.postgresql.org/docs/9.4/static/errcodes-appendix.html
Kelemahan dari penanganan pengecualian dengan ORM seperti EF adalah bahwa hal itu hanya akan bekerja dengan backend basis data tertentu. Jika Anda pernah ingin beralih ke SQL server atau yang lain ini tidak akan berfungsi lagi karena kode kesalahan akan berubah.
Tidak memformat pengecualian dengan benar untuk pengguna akhir dapat memaparkan beberapa hal yang tidak ingin dilihat oleh siapa pun selain oleh pengembang.
Terkait:
https://stackoverflow.com/questions/308905/should-there-be-a-ttransaction-for-read-queries
sumber
Child with id {parent.ChildId} could not be found.
. Dan memformat "Pelanggaran kunci asing" Saya pikir lebih buruk dalam kasus ini.Jawaban:
Agak pertanyaan yang membingungkan, tapi YA Anda harus memeriksa dulu dan tidak hanya menangani pengecualian DB.
Pertama-tama, dalam contoh Anda, Anda berada di lapisan data, menggunakan EF langsung pada database untuk menjalankan SQL. Kode Anda sama dengan menjalankan
Alternatif yang Anda sarankan adalah:
Menggunakan pengecualian untuk menjalankan logika kondisional lambat dan secara universal disukai.
Anda memang memiliki kondisi balapan dan harus menggunakan transaksi. Tapi ini bisa sepenuhnya dilakukan dalam kode.
Kuncinya adalah bertanya pada diri sendiri:
Jika tidak, maka pastikan, sisipkan dan buang pengecualian. Tetapi hanya menangani pengecualian seperti kesalahan lain yang mungkin terjadi.
Jika Anda mengharapkannya terjadi, maka itu TIDAK luar biasa dan Anda harus memeriksa untuk melihat apakah anak itu ada terlebih dahulu, merespons dengan pesan ramah yang sesuai jika tidak.
Sunting - Ada banyak kontroversi mengenai ini sepertinya. Sebelum Anda downvote pertimbangkan:
A. Bagaimana jika ada dua kendala FK. Apakah Anda menganjurkan parsing pesan pengecualian untuk mengetahui objek yang hilang?
B. Jika Anda kehilangan, hanya satu pernyataan SQL yang dijalankan. Hanya klik yang mengeluarkan biaya tambahan dari kueri kedua.
C. Biasanya ID akan menjadi kunci pengganti, Sulit membayangkan situasi di mana Anda tahu satu dan Anda tidak cukup yakin itu pada DB. Memeriksa akan aneh. Tetapi bagaimana jika itu adalah kunci alami yang diketik pengguna? Itu bisa memiliki peluang tinggi untuk tidak hadir
sumber
Memeriksa keunikan dan kemudian pengaturan adalah antipattern; selalu dapat terjadi bahwa ID dimasukkan bersamaan antara waktu pemeriksaan dan waktu penulisan. Database dilengkapi untuk menangani masalah ini melalui mekanisme seperti kendala dan transaksi; kebanyakan bahasa pemrograman tidak. Oleh karena itu, jika Anda menghargai konsistensi data, serahkan ke ahlinya (basis data), yaitu melakukan penyisipan dan menangkap pengecualian jika itu terjadi.
sumber
Saya pikir apa yang Anda sebut "gagal cepat" dan apa yang saya sebut itu tidak sama.
Memberitahu database untuk membuat perubahan dan menangani kegagalan, itu cepat. Cara Anda rumit, lambat, dan tidak terlalu andal.
Teknik Anda itu tidak cepat gagal, itu "prelighting". Terkadang ada alasan bagus, tetapi tidak ketika Anda menggunakan database.
sumber
Ini dimulai sebagai komentar tetapi tumbuh terlalu besar.
Tidak, seperti yang dinyatakan oleh jawaban lain, pola ini tidak boleh digunakan. *
Ketika berhadapan dengan sistem yang menggunakan komponen asinkron, akan selalu ada kondisi ras di mana database (atau sistem file, atau sistem async lainnya) dapat berubah antara cek dan perubahan. Pemeriksaan jenis ini sama sekali bukan cara yang dapat diandalkan untuk mencegah jenis kesalahan yang tidak ingin Anda tangani.
Lebih buruk daripada tidak mencukupi, sekilas itu memberi kesan bahwa itu harus mencegah kesalahan rekaman duplikat memberikan rasa aman yang salah.
Anda tetap membutuhkan penanganan kesalahan.
Dalam komentar Anda telah bertanya bagaimana jika Anda membutuhkan data dari berbagai sumber.
Masih tidak.
Itu mendasar tidak hilang jika apa yang ingin Anda periksa menjadi lebih kompleks.
Anda masih membutuhkan penanganan kesalahan.
Bahkan jika pemeriksaan ini adalah cara yang dapat diandalkan untuk mencegah kesalahan tertentu yang Anda coba lindungi, kesalahan lain masih dapat terjadi. Apa yang terjadi jika Anda kehilangan koneksi ke database, atau kehabisan ruang, atau?
Anda mungkin masih membutuhkan penanganan kesalahan terkait database lainnya . Penanganan kesalahan khusus ini mungkin harus menjadi bagian kecil darinya.
Jika Anda membutuhkan data untuk menentukan apa yang harus diubah, Anda jelas perlu mengumpulkannya dari suatu tempat. (tergantung pada alat apa yang Anda gunakan, mungkin ada cara yang lebih baik daripada permintaan terpisah untuk mengumpulkannya) Jika, dalam memeriksa data yang Anda kumpulkan, Anda menentukan bahwa Anda tidak perlu melakukan perubahan setelah semua, bagus, jangan membuat perubahan. Penentuan ini benar-benar terpisah dari masalah penanganan kesalahan.
Anda masih membutuhkan penanganan kesalahan.
Saya tahu saya berulang-ulang tetapi saya merasa penting untuk menjelaskannya. Saya sudah membersihkan kekacauan ini sebelumnya.
Ini akan gagal pada akhirnya. Ketika gagal, akan sulit dan memakan waktu untuk sampai ke dasar. Menyelesaikan masalah yang timbul dari kondisi balapan sulit. Mereka tidak terjadi secara konsisten, sehingga akan sulit atau bahkan tidak mungkin untuk mereproduksi secara terpisah. Anda tidak melakukan penanganan kesalahan yang tepat untuk memulai sehingga Anda tidak akan punya banyak hal untuk dilanjutkan: Mungkin laporan pengguna akhir tentang beberapa teks rahasia (yang Anda coba untuk mencegah agar tidak melihatnya sejak awal.) Mungkin jejak tumpukan yang menunjuk kembali ke fungsi itu yang ketika Anda melihatnya terang-terangan menyangkal kesalahan bahkan mungkin terjadi.
* Mungkin ada alasan bisnis yang sah untuk melakukan pemeriksaan yang ada ini, seperti untuk mencegah aplikasi menggandakan pekerjaan yang mahal, tetapi itu bukan pengganti yang cocok untuk penanganan kesalahan yang tepat.
sumber
Saya pikir hal kedua yang perlu diperhatikan di sini - salah satu alasan Anda menginginkan ini adalah agar Anda dapat memformat pesan kesalahan agar dapat dilihat pengguna.
Saya sungguh-sungguh merekomendasikan Anda:
a) menunjukkan kepada pengguna akhir pesan kesalahan umum yang sama untuk setiap kesalahan yang terjadi.
b) mencatat pengecualian aktual di suatu tempat yang hanya dapat diakses oleh pengembang (jika di server) atau di suatu tempat yang dapat dikirim kepada Anda dengan alat pelaporan kesalahan (jika digunakan klien)
c) jangan mencoba dan memformat detail pengecualian kesalahan yang Anda catat kecuali Anda dapat menambahkan lebih banyak informasi berguna. Anda tidak ingin secara tidak sengaja 'memformat' satu informasi penting yang dapat Anda gunakan untuk melacak masalah.
Singkatnya - pengecualian penuh dengan informasi teknis yang sangat berguna. Semua ini tidak boleh untuk pengguna akhir dan Anda kehilangan informasi ini atas risiko Anda.
sumber