Ketika saya menyimpan entitas dengan kerangka entitas, saya secara alami berasumsi itu hanya akan mencoba untuk menyimpan entitas yang ditentukan. Namun, entitas juga mencoba menyelamatkan entitas anak entitas tersebut. Ini menyebabkan segala macam masalah integritas. Bagaimana cara memaksa EF untuk hanya menyimpan entitas yang ingin saya simpan dan karena itu mengabaikan semua objek turunan?
Jika saya secara manual menyetel properti ke nol, saya mendapatkan pesan kesalahan "Operasi gagal: Hubungan tidak dapat diubah karena satu atau lebih properti kunci asing tidak dapat dibatalkan." Ini sangat kontraproduktif karena saya menetapkan objek anak ke nol secara khusus sehingga EF akan membiarkannya.
Mengapa saya tidak ingin menyimpan / menyisipkan objek anak?
Karena ini sedang dibahas bolak-balik di komentar, saya akan memberikan beberapa pembenaran mengapa saya ingin objek anak saya dibiarkan sendiri.
Dalam aplikasi yang saya buat, model objek EF tidak dimuat dari database tetapi digunakan sebagai objek data yang saya isi saat mengurai file datar. Dalam kasus objek anak, banyak di antaranya merujuk ke tabel pemeta yang mendefinisikan berbagai properti dari tabel induk. Misalnya, lokasi geografis dari entitas utama.
Karena saya telah mengisi objek ini sendiri, EF mengasumsikan ini adalah objek baru dan perlu disisipkan bersama dengan objek induk. Namun, definisi ini sudah ada dan saya tidak ingin membuat duplikat di database. Saya hanya menggunakan objek EF untuk melakukan pencarian dan mengisi kunci asing di entitas tabel utama saya.
Bahkan dengan objek anak yang merupakan data nyata, saya perlu menyimpan induknya terlebih dahulu dan mendapatkan kunci utama atau EF sepertinya akan membuat kekacauan. Semoga ini memberi penjelasan.
sumber
Jawaban:
Sejauh yang saya tahu, Anda memiliki dua opsi.
Pilihan 1)
Hapus semua objek anak, ini akan memastikan EF tidak menambahkan apapun. Ini juga tidak akan menghapus apapun dari database Anda.
Pilihan 2)
Tetapkan objek anak sebagai terlepas dari konteks menggunakan kode berikut
Perhatikan bahwa Anda tidak dapat melepaskan
List
/Collection
. Anda harus mengulang daftar Anda dan melepaskan setiap item dalam daftar Anda seperti itusumber
Singkat cerita: Gunakan kunci Asing dan itu akan menghemat hari Anda.
Misalnya Anda memiliki entitas Sekolah dan entitas Kota , dan ini adalah hubungan banyak ke satu di mana Kota memiliki banyak Sekolah dan Sekolah milik Kota. Dan asumsikan Cities sudah ada di tabel pemeta sehingga Anda TIDAK ingin kota tersebut disisipkan lagi saat memasukkan sekolah baru.
Awalnya Anda mungkin mendefinisikan entitas Anda seperti ini:
Dan Anda mungkin melakukan penyisipan Sekolah seperti ini (asumsikan Anda sudah memiliki properti Kota yang ditetapkan ke item baru ):
Pendekatan di atas dapat bekerja dengan sempurna dalam kasus ini, namun, saya lebih suka pendekatan Kunci Asing yang menurut saya lebih jelas dan fleksibel. Lihat solusi terbaru di bawah ini:
Dengan cara ini, Anda secara eksplisit mendefinisikan bahwa Sekolah memiliki kunci asing City_Id dan mengacu pada entitas Kota . Jadi, jika menyangkut penyisipan Sekolah , Anda dapat melakukan:
Dalam kasus ini, Anda secara eksplisit menentukan City_Id dari record baru dan menghapus City dari grafik sehingga EF tidak akan repot-repot menambahkannya ke konteks bersama dengan Sekolah .
Meskipun pada kesan pertama pendekatan kunci Asing tampak lebih rumit, tetapi percayalah, mentalitas ini akan menghemat banyak waktu ketika harus memasukkan hubungan banyak-ke-banyak (bayangkan Anda memiliki hubungan Sekolah dan Siswa, dan Siswa memiliki properti Kota) dan seterusnya.
Semoga ini bisa membantu Anda.
sumber
[Range(1, int.MaxValue)]
atribut?Jika Anda hanya ingin menyimpan perubahan pada orangtua objek dan menghindari menyimpan perubahan ke salah satu nya anak objek, maka mengapa tidak hanya melakukan hal berikut:
Baris pertama menempelkan objek induk dan seluruh grafik objek turunan dependennya ke konteks dalam
Unchanged
status.Baris kedua mengubah status untuk objek induk saja, membiarkan turunannya dalam
Unchanged
status.Perhatikan bahwa saya menggunakan konteks yang baru dibuat, jadi ini menghindari penyimpanan perubahan lain ke database.
sumber
Salah satu solusi yang disarankan adalah menetapkan properti navigasi dari konteks database yang sama. Dalam solusi ini, properti navigasi yang ditetapkan dari luar konteks database akan diganti. Silakan lihat contoh berikut untuk ilustrasi.
Menyimpan ke database:
Microsoft mendaftarkan ini sebagai fitur, namun menurut saya ini mengganggu. Jika objek departemen yang terkait dengan objek perusahaan memiliki Id yang sudah ada di database, mengapa EF tidak mengaitkan objek perusahaan dengan objek database saja? Mengapa kita perlu mengurus pergaulan sendiri? Menjaga properti navigasi selama menambahkan objek baru adalah sesuatu seperti memindahkan operasi database dari SQL ke C #, merepotkan pengembang.
sumber
Pertama, Anda perlu tahu bahwa ada dua cara untuk memperbarui entitas di EF.
Dalam aplikasi yang saya buat, model objek EF tidak dimuat dari database tetapi digunakan sebagai objek data yang saya isi saat mengurai file datar.
Itu berarti Anda bekerja dengan objek terputus, tetapi tidak jelas apakah Anda menggunakan asosiasi independen atau asosiasi kunci asing .
Menambahkan
Saat menambahkan entitas baru dengan objek anak yang sudah ada (objek yang ada di database), jika objek anak tidak dilacak oleh EF, objek anak akan disisipkan kembali. Kecuali jika Anda memasang objek anak secara manual terlebih dahulu.
Memperbarui
Anda cukup menandai entitas sebagai diubah, kemudian semua properti skalar akan diperbarui dan properti navigasi akan diabaikan begitu saja.
Grafik Diff
Jika Anda ingin menyederhanakan kode saat bekerja dengan objek terputus, Anda dapat mencoba untuk membuat grafik di perpustakaan diff .
Berikut adalah pendahuluan, Memperkenalkan GraphDiff untuk Kode Kerangka Entitas Pertama - Mengizinkan pembaruan otomatis dari grafik entitas yang terpisah .
Kode sampel
Masukkan entitas jika tidak ada, jika tidak perbarui.
Sisipkan entitas jika tidak ada, jika tidak, perbarui DAN sisipkan objek anak jika tidak ada, jika tidak perbarui.
sumber
Cara terbaik untuk melakukannya adalah dengan menimpa fungsi SaveChanges di konteks data Anda.
sumber
Saya mendapat masalah yang sama ketika saya mencoba menyimpan profil, saya sudah salam tabel dan baru membuat profil. Ketika saya memasukkan profil, itu juga dimasukkan ke dalam salam. Jadi saya mencoba seperti ini sebelum savechanges ().
db.Entry (Profile.Salutation) .State = EntityState.Unchanged;
sumber
Ini berhasil untuk saya:
sumber
Apa yang telah kita lakukan adalah sebelum menambahkan induk ke dbset, memutuskan koleksi anak dari induk, memastikan untuk mendorong koleksi yang ada ke variabel lain untuk memungkinkan bekerja dengannya nanti, dan kemudian mengganti koleksi anak saat ini dengan koleksi kosong baru. Menyetel koleksi anak ke nol / tidak ada yang gagal bagi kami. Setelah melakukan itu, tambahkan induk ke dbset. Dengan cara ini anak-anak tidak ditambahkan sampai Anda menginginkannya.
sumber
Saya tahu itu posting lama namun jika Anda menggunakan pendekatan kode-pertama Anda dapat mencapai hasil yang diinginkan dengan menggunakan kode berikut di file pemetaan Anda.
Ini pada dasarnya akan memberitahu EF untuk mengecualikan properti "ChildObjectOrCollection" dari model sehingga tidak dipetakan ke database.
sumber
Saya memiliki tantangan serupa menggunakan Entity Framework Core 3.1.0, logika repo saya cukup umum.
Ini berhasil untuk saya:
Harap diperhatikan "ParentEntityId" adalah nama kolom kunci asing pada entitas anak. Saya menambahkan baris kode yang disebutkan di atas pada metode ini:
sumber