Alasan kesalahan dalam kode yang disediakan adalah sebagai berikut.
Ketika Anda membuat entitas Adari database, propertinya Sdiinisialisasi dengan koleksi yang berisi dua catatan baru B. Iddari masing-masing Bentitas baru ini sama dengan 0.
// This line of code reads entity from the database
// and creates new instance of object A from it.
var a = db.Set<A>().Single();
// When new entity A is created its field S initialized
// by a collection that contains two new instances of entity B.
// Property Id of each of these two B entities is equal to 0.
public ICollection<B> S { get; set; } = new List<B>() { new B {}, new B {} };
Setelah mengeksekusi baris var a = db.Set<A>().Single()pengumpulan kode Sentitas Atidak mengandung Bentitas dari database, karena DbContext Dbtidak menggunakan lazy loading dan tidak ada pemuatan eksplisit koleksi S. Entitas Ahanya berisi Bentitas baru yang dibuat selama inisialisasi koleksi S.
Saat Anda menelepon IsModifed = trueuntuk Skerangka kerja entitas kumpulan mencoba menambahkan dua entites baru Bke dalam pelacakan perubahan. Tetapi gagal karena kedua Bentitas baru memiliki hal yang sama Id = 0:
// This line tries to add to change tracking two new B entities with the same Id = 0.
// As a result it fails.
db.Entry(a).Collection(x => x.S).IsModified = true;
Anda bisa melihat dari jejak tumpukan yang dicoba ditambahkan kerangka kerja Bentitas ke IdentityMap:
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.IdentityMap`1.ThrowIdentityConflict(InternalEntityEntry entry)
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.IdentityMap`1.Add(TKey key, InternalEntityEntry entry, Boolean updateDuplicate)
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.IdentityMap`1.Add(TKey key, InternalEntityEntry entry)
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.IdentityMap`1.Add(InternalEntityEntry entry)
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.StartTracking(InternalEntityEntry entry)
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.InternalEntityEntry.SetPropertyModified(IProperty property, Boolean changeState, Boolean isModified, Boolean isConceptualNull, Boolean acceptChanges)
at Microsoft.EntityFrameworkCore.ChangeTracking.NavigationEntry.SetFkPropertiesModified(InternalEntityEntry internalEntityEntry, Boolean modified)
at Microsoft.EntityFrameworkCore.ChangeTracking.NavigationEntry.SetFkPropertiesModified(Object relatedEntity, Boolean modified)
at Microsoft.EntityFrameworkCore.ChangeTracking.NavigationEntry.set_IsModified(Boolean value)
Dan pesan kesalahan juga memberitahu bahwa ia tidak dapat melacak Bentitas dengan Id = 0karena Bentitas lain dengan yang sama Idsudah dilacak.
Cara mengatasi masalah ini.
Untuk mengatasi masalah ini, Anda harus menghapus kode yang membuat Bentitas saat menginisialisasi Skoleksi:
public ICollection<B> S { get; set; } = new List<B>();
Sebaliknya Anda harus mengisi Skoleksi di tempat di mana Adibuat. Sebagai contoh:
db.Add(new A {S = {new B(), new B()}});
Jika Anda tidak menggunakan lazy loading, Anda harus secara eksplisit memuat Skoleksi untuk menambahkan itemnya ke dalam pelacakan perubahan:
// Use eager loading, for example.
A a = db.Set<A>().Include(x => x.S).Single();
db.Entry(a).Collection(x => x.S).IsModified = true;
Mengapa itu tidak menambah dan bukannya melampirkan contoh B?
Singkatnya , mereka dilampirkan untuk ditambahkan karena mereka memiliki Detachedkeadaan.
Setelah mengeksekusi baris kode
var a = db.Set<A>().Single();
instance entitas yang dibuat Bmemiliki status Detached. Itu dapat diverifikasi menggunakan kode selanjutnya:
Console.WriteLine(db.Entry(a.S[0]).State);
Console.WriteLine(db.Entry(a.S[1]).State);
Lalu ketika Anda mengatur
db.Entry(a).Collection(x => x.S).IsModified = true;
EF mencoba menambahkan Bentitas untuk mengubah pelacakan. Dari kode sumber EFCore, Anda dapat melihat bahwa ini mengarahkan kami ke metode InternalEntityEntry.SetPropertyModified dengan nilai argumen berikut:
property- salah satu Bentitas kami ,
changeState = true,
isModified = true,
isConceptualNull = false,
acceptChanges = true.
Metode ini dengan argumen seperti itu mengubah keadaan dari Detached Bentit ke Modified, dan kemudian mencoba untuk memulai pelacakan untuk mereka (lihat baris 490 - 506). Karena Bentitas sekarang memiliki status Modifiedini menyebabkan mereka harus dilampirkan (tidak ditambahkan).