ini mungkin pertanyaan yang sepele, tetapi: Karena kerangka kerja entitas ADO.NET secara otomatis melacak perubahan (dalam entitas yang dihasilkan) dan oleh karena itu mempertahankan nilai asli, bagaimana saya dapat mengembalikan perubahan yang dibuat pada objek entitas?
Saya memiliki formulir yang memungkinkan pengguna untuk mengedit sekumpulan entitas "Pelanggan" dalam tampilan kisi.
Sekarang saya memiliki dua tombol "Terima" dan "Kembalikan": jika "Terima" diklik, saya memanggil Context.SaveChanges()
dan objek yang diubah ditulis kembali ke database. Jika "Kembalikan" diklik, saya ingin semua objek mendapatkan nilai properti aslinya. Apa kode untuk itu?
Terima kasih
sumber
Context.Refresh()
adalah contoh tandingan untuk klaim Anda bahwa tidak ada operasi pengembalian? MenggunakanRefresh()
tampaknya pendekatan yang lebih baik (yaitu lebih mudah ditargetkan pada entitas tertentu) daripada membuang konteks dan kehilangan semua perubahan yang terlacak.Query ChangeTracker dari DbContext untuk item kotor. Setel status item yang dihapus menjadi tidak berubah dan tambahkan item ke terlepas. Untuk item yang dimodifikasi, gunakan nilai asli dan setel nilai entri saat ini. Terakhir, setel status entri yang diubah menjadi tidak berubah:
sumber
State
ke EntityState.Unchanged juga akan menimpa semua nilaiOriginal Values
sehingga tidak perlu memanggilSetValues
metode.Mengakui MSDN :
Perhatikan bahwa mengembalikan melalui permintaan ke database memiliki beberapa kekurangan:
sumber
Ini berhasil untuk saya:
Di mana
item
entitas pelanggan akan dikembalikan.sumber
Cara mudah tanpa melacak perubahan apa pun. Ini harus lebih cepat daripada melihat setiap entitas.
sumber
Rollback
prosedur di atas , yang menjadikannya pilihan yang jauh lebih baik jika seseorang ingin mengembalikan seluruh status database. Rollback bisa memilih ceri.50ms+0*n= 50ms
. O (n) artinya performansi dipengaruhi oleh jumlah objek ... performanya mungkin2ms+0.5ms*n
... jadi di bawah 96 objek akan lebih cepat tetapi waktu akan meningkat secara linier dengan jumlah data.Itu berhasil untuk saya. Namun Anda harus memuat ulang data Anda dari konteks untuk membawa data lama. Sumber di sini
sumber
"Ini berhasil untuk saya:
Di mana
item
entitas pelanggan akan dikembalikan. "Saya telah melakukan pengujian dengan ObjectContext.Refresh di SQL Azure, dan "RefreshMode.StoreWins" menjalankan kueri terhadap database untuk setiap entitas dan menyebabkan kebocoran kinerja. Berdasarkan dokumentasi microsoft ():
ClientWins: Perubahan properti yang dibuat ke objek dalam konteks objek tidak diganti dengan nilai dari sumber data. Pada panggilan berikutnya ke SaveChanges, perubahan ini dikirim ke sumber data.
StoreWins: Perubahan properti yang dibuat pada objek dalam konteks objek diganti dengan nilai dari sumber data.
ClientWins juga bukan ide yang bagus, karena mengaktifkan .SaveChanges akan menjalankan perubahan yang "dibuang" ke sumber data.
Saya belum tahu cara terbaik apa, karena membuang konteks dan membuat yang baru menyebabkan pengecualian dengan pesan: "Penyedia yang mendasari gagal saat dibuka" ketika saya mencoba menjalankan kueri apa pun pada konteks baru yang dibuat.
salam,
Henrique Clausing
sumber
Bagi saya, metode yang lebih baik untuk melakukannya adalah mengatur
EntityState.Unchanged
setiap entitas yang ingin Anda batalkan perubahannya. Ini memastikan perubahan dikembalikan pada FK dan memiliki sintaks yang sedikit lebih jelas.sumber
Saya menemukan ini berfungsi dengan baik dalam konteks saya:
Context.ObjectStateManager.ChangeObjectState(customer, EntityState.Unchanged);
sumber
DbContext.SaveChanges()
, tetapi tidak akan mengembalikan nilai entitas ke nilai aslinya. Dan jika status entitas menjadi dimodifikasi dari perubahan selanjutnya, mungkin semua modifikasi sebelumnya akan dipertahankan setelah disimpan?Ini adalah contoh dari apa yang Mrnka bicarakan. Metode berikut menimpa nilai entitas saat ini dengan nilai aslinya dan tidak memanggil database. Kami melakukan ini dengan menggunakan properti OriginalValues dari DbEntityEntry, dan menggunakan refleksi untuk menyetel nilai dengan cara yang umum. (Ini berfungsi pada EntityFramework 5.0)
sumber
Kami menggunakan EF 4, dengan konteks Objek Legacy. Tak satu pun dari solusi di atas secara langsung menjawab ini untuk saya - meskipun itu DID menjawabnya dalam jangka panjang dengan mendorong saya ke arah yang benar.
Kita tidak bisa begitu saja membuang dan membangun kembali konteks karena beberapa objek yang kita miliki di dalam memori (sialan itu pemuatan lambat !!) masih melekat pada konteks tetapi memiliki turunan yang belum dimuat. Untuk kasus ini, kita perlu mengembalikan semuanya ke nilai asli tanpa memalu database dan tanpa memutuskan koneksi yang ada.
Di bawah ini adalah solusi kami untuk masalah yang sama ini:
Saya harap ini membantu orang lain.
sumber
Beberapa ide bagus di atas, saya memilih untuk menerapkan ICloneable dan kemudian metode ekstensi sederhana.
Ditemukan di sini: Bagaimana cara mengkloning daftar generik di C #?
Untuk digunakan sebagai:
Dengan cara ini saya dapat mengkloning daftar entitas produk saya, menerapkan diskon ke setiap item dan tidak perlu khawatir tentang mengembalikan perubahan apa pun pada entitas asli. Tidak perlu berbicara dengan DBContext dan meminta penyegaran atau bekerja dengan ChangeTracker. Anda mungkin mengatakan saya tidak menggunakan EF6 sepenuhnya tetapi ini adalah implementasi yang sangat bagus dan sederhana dan menghindari serangan DB. Saya tidak bisa mengatakan apakah ini memiliki kinerja yang sukses atau tidak.
sumber