Singkatnya, pengecualian dilemparkan selama model pembungkus POSTing dan mengubah status satu entri menjadi 'Dimodifikasi'. Sebelum mengubah status, status disetel ke 'Terpisah' tetapi memanggil Attach () tidak memunculkan kesalahan yang sama. Saya menggunakan EF6.
Silakan temukan kode saya di bawah ini (nama model telah diubah agar lebih mudah dibaca)
Model
// Wrapper classes
public class AViewModel
{
public A a { get; set; }
public List<B> b { get; set; }
public C c { get; set; }
}
Kontroler
public ActionResult Edit(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
if (!canUserAccessA(id.Value))
return new HttpStatusCodeResult(HttpStatusCode.Forbidden);
var aViewModel = new AViewModel();
aViewModel.A = db.As.Find(id);
if (aViewModel.Receipt == null)
{
return HttpNotFound();
}
aViewModel.b = db.Bs.Where(x => x.aID == id.Value).ToList();
aViewModel.Vendor = db.Cs.Where(x => x.cID == aViewModel.a.cID).FirstOrDefault();
return View(aViewModel);
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(AViewModel aViewModel)
{
if (!canUserAccessA(aViewModel.a.aID) || aViewModel.a.UserID != WebSecurity.GetUserId(User.Identity.Name))
return new HttpStatusCodeResult(HttpStatusCode.Forbidden);
if (ModelState.IsValid)
{
db.Entry(aViewModel.a).State = EntityState.Modified; //THIS IS WHERE THE ERROR IS BEING THROWN
db.SaveChanges();
return RedirectToAction("Index");
}
return View(aViewModel);
}
Seperti yang ditunjukkan di atas garis
db.Entry(aViewModel.a).State = EntityState.Modified;
melempar pengecualian:
Gagal melampirkan entitas jenis 'A' karena entitas lain dengan jenis yang sama sudah memiliki nilai kunci utama yang sama. Hal ini dapat terjadi saat menggunakan metode 'Lampirkan' atau menyetel status entitas menjadi 'Tidak Berubah' atau 'Dimodifikasi' jika ada entitas dalam grafik yang memiliki nilai kunci yang bertentangan. Ini mungkin karena beberapa entitas baru dan belum menerima nilai kunci yang dihasilkan database. Dalam kasus ini, gunakan metode 'Tambah' atau status entitas 'Ditambahkan' untuk melacak grafik dan kemudian setel status entitas bukan baru ke 'Tidak Berubah' atau 'Dimodifikasi' yang sesuai.
Adakah yang melihat ada yang salah dalam kode saya atau memahami dalam keadaan apa kesalahan tersebut akan terjadi saat mengedit model?
sumber
EntityState
? Karena entitas Anda berasal dari permintaan posting, itu tidak boleh dilacak oleh konteks saat ini, saya rasa itu menganggap bahwa Anda mencoba menambahkan item dengan ID yang adadb
instance sama di antara dua tindakan Anda, ini dapat menjelaskan masalah Anda, karena item Anda dimuat dengan metode GET (kemudian dilacak oleh konteksnya), dan mungkin tidak mengenali yang ada di metode POST Anda sebagai entitas yang diambil sebelumnya .canUserAccessA()
memuat entitas secara langsung atau sebagai relasi dari entitas lain?Jawaban:
Masalah TERSELESAIKAN!
Attach
Metode berpotensi dapat membantu seseorang tetapi tidak akan membantu dalam situasi ini karena dokumen sudah dilacak saat dimuat dalam fungsi pengontrol Edit GET. Lampirkan akan menampilkan kesalahan yang persis sama.Masalah yang saya temui di sini disebabkan oleh fungsi
canUserAccessA()
yang memuat entitas A sebelum memperbarui status objek a. Ini mengacaukan entitas yang dilacak dan itu mengubah status objek menjadiDetached
.Solusinya adalah mengubah
canUserAccessA()
sehingga objek yang saya muat tidak akan terlacak. FungsiAsNoTracking()
harus dipanggil saat menanyakan konteks.Untuk beberapa alasan saya tidak dapat menggunakan
.Find(aID)
denganAsNoTracking()
tetapi tidak terlalu penting karena saya dapat mencapai hal yang sama dengan mengubah kueri.Semoga ini akan membantu siapa pun dengan masalah serupa!
sumber
using System.Data.Entity;
menggunakanAsNoTracking()
.Menariknya:
Atau jika Anda masih tidak umum:
sepertinya menyelesaikan masalah saya dengan lancar.
sumber
AddOrUpdate
adalah metode ekstensi diSystem.Data.Entity.Migrations
namespace.Tampaknya entitas yang Anda coba ubah tidak dilacak dengan benar dan oleh karena itu tidak dikenali sebagai diedit, melainkan ditambahkan.
Alih-alih langsung menyetel status, coba lakukan hal berikut:
Selain itu, saya ingin memperingatkan Anda bahwa kode Anda mengandung potensi kerentanan keamanan. Jika Anda menggunakan entitas secara langsung dalam model tampilan Anda, maka Anda berisiko bahwa seseorang dapat mengubah konten entitas dengan menambahkan bidang yang diberi nama dengan benar dalam formulir yang dikirimkan. Misalnya, jika pengguna menambahkan kotak input dengan nama "A.FirstName" dan entitas berisi bidang tersebut, maka nilai akan terikat ke viewmodel dan disimpan ke database bahkan jika pengguna tidak diizinkan untuk mengubahnya dalam operasi normal aplikasi .
Memperbarui:
Untuk mengatasi kerentanan keamanan yang disebutkan sebelumnya, Anda tidak boleh mengekspos model domain Anda sebagai model tampilan, tetapi gunakan model tampilan terpisah sebagai gantinya. Kemudian tindakan Anda akan menerima viewmodel yang dapat Anda petakan kembali ke model domain menggunakan beberapa alat pemetaan seperti AutoMapper. Ini akan membuat Anda aman dari pengguna yang mengubah data sensitif.
Berikut penjelasan lengkapnya:
http://www.stevefenton.co.uk/Content/Blog/Date/201303/Blog/Why-You-Never-Expose-Your-Domain-Model-As-Your-MVC-Model/
sumber
Coba ini:
sumber
bagi saya salinan lokal adalah sumber masalahnya. ini menyelesaikannya
sumber
Kasus saya adalah saya tidak memiliki akses langsung ke konteks EF dari aplikasi MVC saya.
Jadi, jika Anda menggunakan beberapa jenis repositori untuk persistensi entitas, mungkin lebih tepat untuk melepaskan entitas yang dimuat secara eksplisit dan kemudian menyetel EntityState yang terikat ke Dimodifikasi.
Contoh kode (abstrak):
MVC
Gudang
sumber
Saya pikir saya akan membagikan pengalaman saya tentang yang satu ini, meskipun saya merasa agak konyol karena tidak menyadarinya lebih awal.
Saya menggunakan pola repositori dengan instance repo yang dimasukkan ke dalam pengontrol saya. Repositori konkret memberi contoh ModelContext saya (DbContext) yang bertahan seumur hidup repositori, yang
IDisposable
dan dibuang oleh pengontrol.Masalah bagi saya adalah saya memiliki versi cap dan baris yang dimodifikasi pada entitas saya, jadi saya mendapatkannya terlebih dahulu untuk membandingkan dengan header masuk. Tentu saja, ini memuat dan melacak entitas yang kemudian diperbarui.
Perbaikannya hanya dengan mengubah repositori dari memperbarui konteks sekali dalam konstruktor menjadi memiliki metode berikut:
Hal ini memungkinkan metode repositori untuk memperbarui instance konteksnya pada setiap penggunaan dengan memanggil
GetDbContext
, atau menggunakan instance sebelumnya jika mereka menginginkannya dengan menetapkan true.sumber
Saya telah menambahkan jawaban ini hanya karena masalahnya dijelaskan berdasarkan pola data yang lebih kompleks dan saya merasa sulit untuk memahami di sini.
Saya membuat aplikasi yang cukup sederhana. Kesalahan ini terjadi di dalam tindakan Edit POST. Tindakan tersebut menerima ViewModel sebagai parameter masukan. Alasan menggunakan ViewModel adalah untuk membuat beberapa kalkulasi sebelum record disimpan.
Setelah tindakan melewati validasi seperti
if(ModelState.IsValid)
, kesalahan saya adalah memproyeksikan nilai dari ViewModel ke dalam instance Entitas yang benar-benar baru. Saya pikir saya harus membuat contoh baru untuk menyimpan data yang diperbarui dan kemudian menyimpan contoh tersebut.Apa yang saya sadari kemudian adalah bahwa saya harus membaca catatan dari database:
dan memperbarui objek ini. Semuanya bekerja sekarang.
sumber
Saya mengalami masalah ini dengan var lokal dan saya hanya melepaskannya seperti ini:
Masalah penyebab objek yang dimuat dengan Key yang sama, maka pertama-tama kita akan melepaskan objek tersebut dan melakukan update untuk menghindari konflik antara dua objek dengan Key yang sama.
sumber
Saya mengalami masalah serupa, setelah menyelidiki selama 2-3 hari ditemukan ".AsNoTracking" harus dihapus karena EF tidak melacak perubahan dan menganggap tidak ada perubahan kecuali ada objek yang dilampirkan. Juga jika kita tidak menggunakan .AsNoTracking, EF secara otomatis mengetahui objek mana yang akan disimpan / diperbarui sehingga tidak perlu menggunakan Attach / Added.
sumber
Gunakan di
AsNoTracking()
mana Anda mendapatkan kueri Anda.sumber
Saya mengalami kesalahan ini di mana
Saya mengubah metode B agar memiliki pernyataan penggunaan dan hanya mengandalkan db2 lokal . Setelah:
sumber
Mirip dengan apa yang dikatakan Luke Puplett, masalah dapat disebabkan oleh tidak tepat membuang atau menciptakan konteks Anda.
Dalam kasus saya, saya memiliki kelas yang menerima konteks yang disebut
ContextService
:Layanan konteks saya memiliki fungsi yang memperbarui entitas menggunakan objek entitas yang dipakai:
Semua ini baik-baik saja, pengontrol saya tempat saya menginisialisasi layanan adalah masalahnya. Pengontrol saya awalnya terlihat seperti ini:
Saya mengubahnya menjadi ini dan kesalahannya hilang:
sumber
Masalah ini juga dapat dilihat selama
ViewModel
untukEntityModel
pemetaan (dengan menggunakanAutoMapper
, dll) dan mencoba untuk memasukkancontext.Entry().State
dancontext.SaveChanges()
sebuah seperti menggunakan blok seperti yang ditunjukkan di bawah ini akan memecahkan masalah. Harap diingat bahwacontext.SaveChanges()
metode ini digunakan dua kali daripada menggunakan setelahif-block
karena harus menggunakan blok juga.Semoga ini membantu...
sumber
Inilah yang saya lakukan dalam kasus serupa.
Situasi itu berarti entitas yang sama telah ada dalam konteks. Jadi berikut ini bisa membantu
Pertama, periksa dari ChangeTracker jika entitas ada dalam konteks
Jika ada
sumber
Saya bisa memperbaiki masalah dengan memperbarui status. ketika Anda memicu pencarian atau operasi kueri lainnya pada catatan yang sama sate telah diperbarui dengan dimodifikasi sehingga kami perlu mengatur status ke Terpisah maka Anda dapat mengaktifkan perubahan pembaruan Anda
sumber
Saya mengatasi masalah ini dengan blok "menggunakan"
Di sinilah saya mendapatkan ide https://social.msdn.microsoft.com/Forums/sqlserver/es-ES/b4b350ba-b0d5-464d-8656-8c117d55b2af/problema-al-modificar-en-entity-framework?forum = vcses dalam bahasa spanyol (cari jawaban kedua)
sumber
Anda dapat menggunakan metode tambahan seperti;
tetapi dalam banyak kasus jika Anda ingin menggunakan lebih dari satu model pada saat itu, ini tidak akan berfungsi karena entitas sudah dilampirkan ke entitas lain. Jadi, saat itu Anda bisa menggunakan metode ADDOrUpdate Entity Migration yang hanya memigrasikan objek dari satu objek ke objek lain dan sebagai hasilnya Anda tidak akan mendapatkan error.
sumber
Hapus semua Status
dbContextGlobalERP.ChangeTracker.Entries (). Di mana (e => e.Entity! = null) .ToList (). ForEach (e => e.State = EntityState.Detached);
sumber