Ketika saya berada dalam skenario terpisah dan mendapatkan dto dari klien yang saya petakan ke dalam entitas untuk menyimpannya, saya melakukan ini:
context.Entry(entity).State = EntityState.Modified;
context.SaveChanges();
Untuk apa kemudian DbSet.Attach(entity)
atau mengapa saya harus menggunakan metode .Attach ketika EntityState.Modified sudah melampirkan entitas?
c#
entity-framework
entity-framework-6
Elisabeth
sumber
sumber
Jawaban:
Saat Anda melakukannya
context.Entry(entity).State = EntityState.Modified;
, Anda tidak hanya melampirkan entitas keDbContext
, Anda juga menandai seluruh entitas sebagai kotor. Ini berarti bahwa ketika Anda melakukannyacontext.SaveChanges()
, EF akan menghasilkan pernyataan pembaruan yang akan memperbarui semua bidang entitas.Ini tidak selalu diinginkan.
Di sisi lain,
DbSet.Attach(entity)
melampirkan entitas ke konteks tanpa menandainya sebagai kotor. Itu setara dengan melakukancontext.Entry(entity).State = EntityState.Unchanged;
Saat melampirkan dengan cara ini, kecuali Anda kemudian melanjutkan untuk memperbarui properti di entitas, saat Anda menelepon lagi
context.SaveChanges()
, EF tidak akan membuat pembaruan database untuk entitas ini.Bahkan jika Anda berencana untuk membuat pembaruan ke entitas, jika entitas memiliki banyak properti (kolom db) tetapi Anda hanya ingin memperbarui beberapa, Anda mungkin merasa menguntungkan untuk melakukan
DbSet.Attach(entity)
, dan kemudian hanya memperbarui beberapa properti yang perlu diperbarui. Melakukannya dengan cara ini akan menghasilkan pernyataan pembaruan yang lebih efisien dari EF. EF hanya akan memperbarui properti yang Anda modifikasi (berbeda dengancontext.Entry(entity).State = EntityState.Modified;
yang akan menyebabkan semua properti / kolom diperbarui)Dokumentasi yang relevan: Tambah / Lampirkan dan Status Entitas .
Contoh kode
Misalkan Anda memiliki entitas berikut:
Jika kode Anda terlihat seperti ini:
SQL yang dihasilkan akan terlihat seperti ini:
Perhatikan bagaimana pernyataan pembaruan di atas akan memperbarui semua kolom, terlepas atau apakah Anda benar-benar mengubah nilainya atau tidak.
Sebaliknya, jika kode Anda menggunakan "normal" Lampirkan seperti ini:
Kemudian pernyataan pembaruan yang dihasilkan berbeda:
Seperti yang Anda lihat, pernyataan pembaruan hanya memperbarui nilai yang benar-benar berubah setelah Anda melampirkan entitas ke konteks. Bergantung pada struktur tabel Anda, ini dapat memiliki dampak kinerja yang positif.
Sekarang, opsi mana yang lebih baik untuk Anda sepenuhnya bergantung pada apa yang Anda coba lakukan.
sumber
WHERE
klausa yang hanya berisi kunci utama, dan tanpa pemeriksaan konkurensi. Untuk melakukan pemeriksaan konkurensi, saya perlu mengonfigurasi kolom secara eksplisit sebagai token konkurensi atau rowVersion. Dalam hal ini,WHERE
klausul hanya akan memiliki kunci utama dan kolom token konkurensi, tidak semua bidang. Jika tes Anda menunjukkan sebaliknya, saya ingin sekali mendengarnya.DbContext.Entry(person).CurrentValues
danDbContext.Entry(person).OriginalValues
.Saat Anda menggunakan
DbSet.Update
metode ini, Entity Framework menandai semua properti entitas Anda sebagaiEntityState.Modified
, jadi lacaklah. Jika Anda ingin mengubah hanya beberapa properti Anda, tidak semuanya, gunakanDbSet.Attach
. Metode ini membuat semua properti AndaEntityState.Unchanged
, jadi Anda harus membuat properti yang ingin Anda perbaruiEntityState.Modified
. Jadi, saat aplikasi mencapaiDbContext.SaveChanges
, itu hanya akan mengoperasikan properti yang dimodifikasi.sumber
Hanya sebagai tambahan (pada jawaban yang ditandai) ada perbedaan penting antara
context.Entry(entity).State = EntityState.Unchanged
dancontext.Attach(entity)
(dalam EF Core):Saya melakukan beberapa tes untuk lebih memahaminya sendiri (oleh karena itu ini juga termasuk beberapa pengujian referensi umum), jadi ini adalah skenario pengujian saya:
QueryTrackingBehavior.NoTracking
Ini adalah modelnya:
Ini adalah data uji (asli) dalam database:
Untuk mendapatkan pesanan:
Sekarang tesnya:
Pembaruan Sederhana dengan EntityState :
Pembaruan Sederhana dengan Lampirkan :
Perbarui dengan mengubah Id-Anak dengan EntityState :
Perbarui dengan mengubah Id Anak dengan Lampirkan :
Catatan: Ini melempar Exception, tidak peduli apakah Id diubah atau disetel ke nilai asli, sepertinya status Id disetel ke "diubah" dan ini tidak diperbolehkan (karena itu kunci utama)
Perbarui dengan mengubah ID Anak sebagai yang baru (tidak ada perbedaan antara EntityState dan Attach):
Catatan: Lihat perbedaan Update dengan EntityState tanpa new (di atas). Kali ini Nama akan diperbarui, karena contoh Pengguna baru.
Perbarui dengan mengubah Reference-Id dengan EntityState :
Perbarui dengan mengubah Referensi-Id dengan Lampirkan :
Catatan: Referensi akan diubah menjadi Pengguna 3, tetapi juga pengguna 1 akan diperbarui, saya kira ini karena
order.OrderedByUser.Id
tidak berubah (masih 1).Kesimpulan Dengan EntityState Anda memiliki kontrol lebih, tetapi Anda harus memperbarui sub-properti (tingkat kedua) sendiri. Dengan Lampirkan Anda dapat memperbarui semuanya (saya kira dengan semua tingkat properti), tetapi Anda harus tetap memperhatikan referensi. Sebagai contoh: Jika User (OrderedByUser) akan menjadi dropDown, mengubah nilai melalui dropDown mungkin menimpa seluruh objek User. Dalam kasus ini, dropDown-Value asli akan ditimpa, bukan referensi.
Bagi saya kasus terbaik adalah mengatur objek seperti OrderedByUser ke null dan hanya mengatur order.OrderedByUserId ke nilai baru, jika saya hanya ingin mengubah referensi (tidak peduli apakah EntityState atau Attach).
Semoga ini bisa membantu, saya tahu teksnya banyak: D
sumber