Sağlanan koddaki hatanın nedeni aşağıdadır.
A
Veritabanından oluşturulmuş varlık aldığınızda, özelliği S
iki yeni kayıt içeren bir koleksiyonla başlatılır B
. Id
bu yeni B
varlıkların her biri eşittir 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 {} };
Kod satırını çalıştırıldıktan sonra var a = db.Set<A>().Single()
koleksiyonun S
varlığın A
içermediğinden B
dolayı, veritabanından varlıkları DbContext Db
tembel yükleme kullanmak ve tahsilat hiçbir açık yükleme var demektir S
. Varlık A
yalnızca B
koleksiyonun başlatılması sırasında oluşturulan yeni varlıkları içerir S
.
IsModifed = true
Koleksiyon S
varlık çağrısı yaparken, bu iki yeni girişi B
değişiklik izlemeye eklemeye çalışır . Ancak başarısız olur, çünkü her iki yeni B
varlık da aynıdır 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;
Sen varlık çerçeve çalışır eklemek için bu yığın izleme görebilirsiniz B
içine varlıkları 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)
Ve hata iletisi de izleyemez söyler B
ile varlık Id = 0
başka nedeni B
ile aynı varlık Id
zaten izlenir.
Bu sorun nasıl giderilir.
Bu sorunu gidermek için koleksiyonu B
başlatırken varlıklar oluşturan kodu silmeniz gerekir S
:
public ICollection<B> S { get; set; } = new List<B>();
Bunun yerine S
koleksiyonu A
oluşturulduğu yere doldurmalısınız . Örneğin:
db.Add(new A {S = {new B(), new B()}});
Tembel yükleme kullanmıyorsanız S
, öğelerini değişiklik izlemeye eklemek için koleksiyonu açıkça yüklemelisiniz :
// Use eager loading, for example.
A a = db.Set<A>().Include(x => x.S).Single();
db.Entry(a).Collection(x => x.S).IsModified = true;
B örneklerini eklemek yerine neden eklemiyor?
Kısacası , eklenmeye meyillidirler çünküDetached
devlete .
Kod satırını yürüttükten sonra
var a = db.Set<A>().Single();
oluşturulan varlık örnekleri B
devlete sahiptir Detached
. Sonraki kod kullanılarak doğrulanabilir:
Console.WriteLine(db.Entry(a.S[0]).State);
Console.WriteLine(db.Entry(a.S[1]).State);
Sonra,
db.Entry(a).Collection(x => x.S).IsModified = true;
EF, B
izlemeyi değiştirmek için varlık eklemeye çalışır . EFC'nin kaynak kodundanDaha fazla bunun bizi bir sonraki argüman değerleriyle InternalEntityEntry.SetPropertyModified yöntemine götürdüğünü görebilirsiniz :
property
- B
varlıklarımızdan biri ,
changeState = true
,
isModified = true
,
isConceptualNull = false
,
acceptChanges = true
.
Bu tür argümanlarla bu yöntem, Detached
B
girişlerin durumunu değiştirir Modified
ve daha sonra onlar için izlemeye başlamaya çalışır (bkz . 490 - 506 satırları ). Çünkü B
tarafların artık devlet var Modified
onları takılacak bu yol (eklenmez).