Saya mendapatkan kesalahan ini ketika saya GetById () pada suatu entitas dan kemudian mengatur koleksi entitas anak ke daftar baru saya yang berasal dari tampilan MVC.
Operasi gagal: Hubungan tidak dapat diubah karena satu atau lebih properti kunci asing tidak dapat dibatalkan. Ketika perubahan dibuat untuk suatu hubungan, properti kunci asing terkait diatur ke nilai nol. Jika kunci asing tidak mendukung nilai nol, hubungan baru harus ditentukan, properti kunci asing harus diberikan nilai bukan nol lainnya, atau objek yang tidak terkait harus dihapus.
Saya tidak begitu mengerti baris ini:
Hubungan tidak dapat diubah karena satu atau lebih properti kunci asing tidak dapat dibatalkan.
Mengapa saya harus mengubah hubungan antara 2 entitas? Itu harus tetap sama sepanjang masa aplikasi secara keseluruhan.
Kode pengecualian terjadi adalah sederhana menetapkan kelas anak yang dimodifikasi dalam koleksi ke kelas induk yang ada. Ini diharapkan akan melayani untuk menghapus kelas anak, penambahan yang baru dan modifikasi. Saya akan berpikir Entity Framework menangani ini.
Baris kode dapat didistilasi ke:
var thisParent = _repo.GetById(1);
thisParent.ChildItems = modifiedParent.ChildItems();
_repo.Save();
Jawaban:
Anda harus menghapus item anak lama
thisParent.ChildItems
satu per satu secara manual. Entity Framework tidak melakukan itu untuk Anda. Akhirnya tidak dapat memutuskan apa yang ingin Anda lakukan dengan item anak lama - jika Anda ingin membuangnya atau jika Anda ingin menyimpan dan menugaskannya ke entitas induk lainnya. Anda harus memberi tahu Kerangka Kerja keputusan Anda. Tetapi salah satu dari dua keputusan ini harus Anda buat karena entitas anak tidak dapat hidup sendiri tanpa referensi ke orang tua mana pun dalam basis data (karena batasan kunci asing). Pada dasarnya itulah yang dikatakan pengecualian.Edit
Apa yang akan saya lakukan jika item anak dapat ditambahkan, diperbarui, dan dihapus:
Catatan: Ini belum diuji. Diasumsikan bahwa koleksi item anak adalah tipe
ICollection
. (Saya biasanya memilikiIList
dan kemudian kode terlihat sedikit berbeda.) Saya juga telah menghapus semua abstraksi repositori agar tetap sederhana.Saya tidak tahu apakah itu solusi yang baik, tetapi saya percaya bahwa beberapa kerja keras di sepanjang garis ini harus dilakukan untuk mengurus semua jenis perubahan dalam koleksi navigasi. Saya juga akan senang melihat cara yang lebih mudah untuk melakukannya.
sumber
Alasan Anda menghadapi ini adalah karena perbedaan antara komposisi dan agregasi .
Dalam komposisi, objek anak dibuat ketika induk dibuat dan dihancurkan ketika induknya dihancurkan . Jadi masa hidupnya dikendalikan oleh orang tuanya. misalnya posting blog dan komentarnya. Jika sebuah posting dihapus, komentarnya harus dihapus. Tidak masuk akal memiliki komentar untuk kiriman yang tidak ada. Sama untuk pesanan dan barang pesanan.
Secara agregasi, objek anak dapat ada terlepas dari induknya . Jika induk dihancurkan, objek anak masih dapat ada, karena dapat ditambahkan ke orangtua yang berbeda nanti. misalnya: hubungan antara daftar putar dan lagu-lagu dalam daftar putar itu. Jika daftar putar dihapus, lagu-lagu tidak boleh dihapus. Mereka dapat ditambahkan ke daftar putar yang berbeda.
Cara Entity Framework membedakan hubungan agregasi dan komposisi adalah sebagai berikut:
Untuk komposisi: ia mengharapkan objek anak memiliki kunci primer komposit (ParentID, ChildID). Ini adalah desain karena ID anak-anak harus berada dalam ruang lingkup orang tua mereka.
Untuk agregasi: ia mengharapkan properti kunci asing di objek anak menjadi nullable.
Jadi, alasan Anda mengalami masalah ini adalah karena cara Anda menetapkan kunci utama di tabel anak Anda. Itu harus komposit, tetapi tidak. Jadi, Entity Framework melihat asosiasi ini sebagai agregasi, yang berarti, ketika Anda menghapus atau menghapus objek anak, itu tidak akan menghapus catatan anak. Itu hanya akan menghapus asosiasi dan menetapkan kolom kunci asing terkait ke NULL (sehingga catatan anak tersebut kemudian dapat dikaitkan dengan orangtua yang berbeda). Karena kolom Anda tidak mengizinkan NULL, Anda mendapatkan pengecualian yang Anda sebutkan.
Solusi:
1- Jika Anda memiliki alasan kuat untuk tidak ingin menggunakan kunci komposit, Anda perlu menghapus objek anak secara eksplisit. Dan ini bisa dilakukan lebih sederhana daripada solusi yang disarankan sebelumnya:
2- Jika tidak, dengan menetapkan kunci utama yang tepat di tabel anak Anda, kode Anda akan terlihat lebih bermakna:
sumber
Ini masalah yang sangat besar. Apa yang sebenarnya terjadi dalam kode Anda adalah ini:
Parent
dari database dan mendapatkan entitas terlampirSekarang solusinya benar-benar tergantung pada apa yang ingin Anda lakukan dan bagaimana Anda ingin melakukannya?
Jika Anda menggunakan ASP.NET MVC Anda dapat mencoba menggunakan UpdateModel atau TryUpdateModel .
Jika Anda hanya ingin memperbarui anak-anak yang ada secara manual, Anda dapat melakukan sesuatu seperti:
Melampirkan sebenarnya tidak diperlukan (mengatur keadaan untuk
Modified
juga akan melampirkan entitas) tapi saya suka karena membuat proses lebih jelas.Jika Anda ingin memodifikasi yang sudah ada, hapus yang ada dan masukkan anak baru, Anda harus melakukan sesuatu seperti:
sumber
.Clone()
. Apakah Anda memiliki kasus dalam pikiran bahwaChildItem
memiliki properti navigasi sub-anak lainnya? Tetapi dalam kasus itu, bukankah kita ingin agar seluruh sub-grafik melekat pada konteks karena kita akan berharap bahwa semua sub-anak adalah objek baru jika anak itu sendiri adalah baru? (Yah, mungkin berbeda dari model ke model, tetapi mari kita asumsikan kasus bahwa anak-anak "tergantung" dari anak seperti anak-anak tergantung dari orang tua.)http://stackoverflow.com/questions/20233994/do-i-need-to-create-a-dbset-for-every-table-so-that-i-can-persist-child-entitie
Saya menemukan jawaban ini jauh lebih bermanfaat untuk kesalahan yang sama. Tampaknya EF tidak suka ketika Anda Hapus, itu lebih suka Hapus.
Anda dapat menghapus koleksi catatan yang dilampirkan ke catatan seperti ini.
Dalam contoh tersebut, semua catatan Detail yang dilampirkan pada Pesanan memiliki Statusnya diatur ke Hapus. (Dalam persiapan untuk Menambahkan kembali Rincian yang diperbarui, sebagai bagian dari pembaruan Pesanan)
sumber
Saya tidak tahu mengapa dua jawaban lainnya begitu populer!
Saya percaya Anda benar dalam mengasumsikan kerangka kerja ORM harus menanganinya - setelah semua, itulah yang dijanjikan untuk diberikan. Kalau tidak, model domain Anda akan rusak oleh masalah kegigihan. NHibernate mengelola ini dengan senang hati jika Anda mengatur pengaturan kaskade dengan benar. Dalam Kerangka Entitas juga dimungkinkan, mereka hanya mengharapkan Anda untuk mengikuti standar yang lebih baik ketika menyiapkan model database Anda, terutama ketika mereka harus menyimpulkan apa yang harus dilakukan cascading:
Anda harus mendefinisikan hubungan orangtua - anak dengan benar dengan menggunakan hubungan pengidentifikasi ".
Jika Anda melakukan ini, Entity Framework tahu objek anak diidentifikasi oleh orang tua, dan oleh karena itu objek itu harus berupa situasi "kaskade-hapus-anak yatim".
Selain yang di atas, Anda mungkin perlu (dari pengalaman NHibernate)
alih-alih mengganti daftar sepenuhnya.
MEMPERBARUI
Komentar @ Slauma mengingatkan saya bahwa entitas yang terpisah adalah bagian lain dari keseluruhan masalah. Untuk mengatasinya, Anda dapat mengambil pendekatan menggunakan pengikat model khusus yang membangun model Anda dengan mencoba memuatnya dari konteks. Posting blog ini menunjukkan contoh apa yang saya maksud.
sumber
parent.ChildItems.Remove
alih-alih_dbContext.ChildItems.Remove
. Masih (EF <= 6) tidak ada dukungan bawaan dari EF untuk menghindari kode panjang seperti yang ada di jawaban lain.return context.Items.Find(id) ?? new Item()
Jika Anda menggunakan AutoMapper dengan Entity Framework pada kelas yang sama, Anda mungkin menemukan masalah ini. Misalnya jika kelas Anda
Ini akan mencoba menyalin kedua properti. Dalam hal ini, ClassBId tidak dapat dibatalkan. Karena AutoMapper akan menyalin
destination.ClassB = input.ClassB;
ini akan menyebabkan masalah.Setel AutoMapper Anda ke Abaikan
ClassB
properti.sumber
Saya baru saja mengalami kesalahan yang sama. Saya memiliki dua tabel dengan hubungan anak induk, tetapi saya mengonfigurasi "pada penghapusan kaskade" pada kolom kunci asing di definisi tabel dari tabel anak. Jadi ketika saya secara manual menghapus baris induk (melalui SQL) di dalam basis data, ia akan secara otomatis menghapus baris turunan.
Namun ini tidak berhasil di EF, kesalahan yang dijelaskan dalam utas ini muncul. Alasan untuk ini adalah, bahwa dalam model data entitas saya (file edmx) properti asosiasi antara orangtua dan tabel anak tidak benar. The
End1 OnDelete
pilihan dikonfigurasi untuk menjadinone
( "End1" dalam model saya adalah akhir yang memiliki keragaman 1).Saya secara manual mengubah
End1 OnDelete
opsi menjadiCascade
dan daripada bekerja. Saya tidak tahu mengapa EF tidak dapat mengambil ini, ketika saya memperbarui model dari basis data (Saya memiliki basis data model pertama).Untuk kelengkapan, ini adalah bagaimana kode saya untuk menghapus terlihat seperti:
Jika saya tidak menetapkan penghapusan kaskade, saya harus menghapus baris anak secara manual sebelum menghapus baris induk.
sumber
Ini terjadi karena Entitas Anak ditandai sebagai Dimodifikasi daripada Dihapus.
Dan modifikasi yang dilakukan EF terhadap Entitas Anak ketika
parent.Remove(child)
dijalankan, cukup mengatur referensi ke induknyanull
.Anda bisa memeriksa EntityState anak dengan mengetikkan kode berikut ke Jendela Langsung Visual Studio saat pengecualian terjadi, setelah menjalankan
SaveChanges()
:di mana X harus diganti oleh Entitas yang dihapus.
Jika Anda tidak memiliki akses ke
ObjectContext
eksekusi_context.ChildEntity.Remove(child)
, Anda bisa menyelesaikan masalah ini dengan menjadikan kunci asing sebagai bagian dari kunci utama di tabel anak.Dengan cara ini, jika Anda mengeksekusi
parent.Remove(child)
, EF akan dengan benar menandai Entity telah Dihapus.sumber
Jenis solusi ini membantu saya:
Penting untuk mengatakan bahwa ini menghapus semua catatan dan memasukkannya lagi. Tapi untuk kasus saya (kurang dari 10) tidak apa-apa.
Saya harap ini membantu.
sumber
Saya mengalami masalah ini hari ini dan ingin berbagi solusi. Dalam kasus saya, solusinya adalah menghapus item Anak sebelum mendapatkan Orang Tua dari database.
Sebelumnya saya melakukannya seperti pada kode di bawah ini. Saya kemudian akan mendapatkan kesalahan yang sama yang tercantum dalam pertanyaan ini.
Apa yang berhasil bagi saya, adalah untuk mendapatkan item anak-anak terlebih dahulu, menggunakan parentId (kunci asing) dan kemudian hapus item-item itu. Maka saya bisa mendapatkan Orang Tua dari database dan pada saat itu, seharusnya tidak memiliki item anak lagi dan saya dapat menambahkan item anak baru.
sumber
Anda harus secara manual menghapus koleksi ChildItems dan menambahkan item baru ke dalamnya:
Setelah itu, Anda dapat memanggil metode ekstensi DeleteOrphans yang akan menangani entitas yatim (harus dipanggil antara metode DetectChanges dan SaveChanges).
sumber
context.DetectChanges();
.Saya sudah mencoba solusi ini dan banyak lainnya, tetapi tidak ada satupun yang berhasil. Karena ini adalah jawaban pertama di google, saya akan menambahkan solusi saya di sini.
Metode yang berhasil bagi saya adalah mengeluarkan hubungan dari gambar selama komit, jadi tidak ada yang bisa dikacaukan EF. Saya melakukan ini dengan menemukan kembali objek induk di DBContext, dan menghapusnya. Karena properti navigasi objek yang ditemukan kembali semuanya nol, hubungan anak-anak diabaikan selama komit.
Perhatikan bahwa ini mengasumsikan kunci asing diset dengan ON DELETE CASCADE, jadi ketika baris induk dihapus, anak-anak akan dibersihkan oleh database.
sumber
Saya menggunakan solusi Mosh , tetapi tidak jelas bagi saya bagaimana menerapkan kunci komposisi dengan benar dalam kode terlebih dahulu.
Jadi, inilah solusinya:
sumber
Saya memiliki masalah yang sama, tetapi saya tahu itu bekerja dengan baik dalam kasus lain, jadi saya mengurangi masalahnya menjadi ini:
Yang harus saya lakukan adalah menjadikan ParentId bagian dari PK komposit untuk menunjukkan bahwa anak-anak tidak dapat hidup tanpa orangtua. Saya menggunakan model DB-first, menambahkan PK dan menandai kolom parentId sebagai EntityKey (jadi, saya harus memperbarui keduanya dalam DB dan EF - tidak yakin apakah EF saja sudah cukup).
Setelah Anda memikirkannya, ini adalah perbedaan yang sangat elegan yang digunakan EF untuk memutuskan apakah anak-anak "masuk akal" tanpa orangtua (dalam hal ini Clear () tidak akan menghapus mereka dan membuang pengecualian kecuali jika Anda mengatur ParentId ke sesuatu yang lain / istimewa ), atau - seperti dalam pertanyaan awal - kami berharap item akan dihapus setelah dihapus dari induknya.
sumber
Masalah ini muncul karena kami mencoba untuk menghapus tabel induk masih ada data tabel anak. Kami memecahkan masalah dengan bantuan penghapusan kaskade.
Dalam model, buat metode dalam kelas dbcontext.
Setelah itu, In Call API kami
Opsi hapus kaskade menghapus tabel induk juga terkait orangtua dengan kode sederhana ini. Cobalah dengan cara sederhana ini.
Hapus Rentang yang digunakan untuk menghapus daftar catatan dalam database Terima kasih
sumber
Saya juga memecahkan masalah saya dengan jawaban Mosh dan saya pikir jawaban PeterB sedikit karena menggunakan enum sebagai kunci asing. Ingatlah bahwa Anda perlu menambahkan migrasi baru setelah menambahkan kode ini.
Saya juga dapat merekomendasikan posting blog ini untuk solusi lain:
http://www.kianryan.co.uk/2013/03/orphaned-child/
Kode:
sumber
Menggunakan solusi Slauma, saya membuat beberapa fungsi umum untuk membantu memperbarui objek anak dan koleksi objek anak.
Semua objek gigih saya mengimplementasikan antarmuka ini
Dengan ini saya menerapkan dua fungsi ini di Repositori saya
Untuk menggunakannya saya lakukan hal berikut:
Semoga ini membantu
EXTRA: Anda juga bisa membuat kelas DbContextExtentions (atau inferface konteks Anda sendiri):
dan gunakan seperti:
sumber
Saya menghadapi masalah yang sama ketika saya akan menghapus catatan saya daripada beberapa masalah terjadi, karena solusi masalah ini adalah bahwa ketika Anda akan menghapus catatan Anda daripada Anda kehilangan sesuatu sebelum menghapus catatan kepala / master Anda harus menulis ke kode untuk hapus detailnya sebelum tajuk / Master Saya harap masalah Anda terselesaikan.
sumber
Saya telah menemui masalah ini sebelum beberapa jam dan mencoba semuanya, tetapi dalam kasus saya solusinya berbeda dari yang tercantum di atas.
Jika Anda menggunakan entitas yang sudah diambil dari database dan mencoba untuk memodifikasi itu anak-anak kesalahan akan terjadi, tetapi jika Anda mendapatkan salinan baru entitas dari database seharusnya tidak ada masalah. Jangan gunakan ini:
Gunakan ini:
sumber