प्रदान किए गए कोड में त्रुटि का कारण इस प्रकार है।
जब आप A
डेटाबेस से निकाय बनाते हैं , तो इसकी संपत्ति S
एक संग्रह के साथ शुरू होती है जिसमें दो नए रिकॉर्ड होते हैं B
। Id
इस नई B
संस्थाओं में से प्रत्येक के बराबर है 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 {} };
इकाई के कोड var a = db.Set<A>().Single()
कलेक्शन S
की लाइन निष्पादित करने के बाद डेटाबेस से इकाइयां A
शामिल नहीं होती हैं B
, क्योंकि DbContext Db
आलसी लोडिंग का उपयोग नहीं होता है और संग्रह का कोई स्पष्ट लोड नहीं होता है S
। इकाई में A
केवल नई B
इकाइयाँ होती हैं जिन्हें संग्रह के आरंभ के दौरान बनाया गया था S
।
जब आप IsModifed = true
संग्रह S
इकाई ढांचे के लिए कॉल करते हैं तो उन दो नए एंटाइट B
को परिवर्तन ट्रैकिंग में जोड़ने की कोशिश करता है । लेकिन यह विफल रहता है क्योंकि दोनों नई B
संस्थाओं में समान है 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;
आप स्टैक ट्रेस से देख सकते हैं कि एंटिटी फ्रेमवर्क B
संस्थाओं में जोड़ने की कोशिश करता है 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)
और त्रुटि संदेश यह भी बताता है कि यह B
इकाई को ट्रैक नहीं कर सकता Id = 0
क्योंकि B
उसी के साथ एक अन्य इकाई Id
पहले से ही ट्रैक है।
इस समस्या को कैसे हल करें।
इस समस्या को हल करने के लिए आपको कोड को हटाना चाहिए जो संग्रह को B
प्रारंभ करते समय इकाइयाँ बनाता है S
:
public ICollection<B> S { get; set; } = new List<B>();
इसके बजाय आपको S
उस जगह पर संग्रह भरना चाहिए जहां A
बनाया गया है। उदाहरण के लिए:
db.Add(new A {S = {new B(), new B()}});
यदि आप आलसी लोडिंग का उपयोग नहीं करते हैं, तो आपको S
अपने आइटम को परिवर्तन ट्रैकिंग में जोड़ने के लिए स्पष्ट रूप से संग्रह लोड करना चाहिए :
// Use eager loading, for example.
A a = db.Set<A>().Include(x => x.S).Single();
db.Entry(a).Collection(x => x.S).IsModified = true;
बी के उदाहरणों को संलग्न करने के बजाय इसे क्यों नहीं जोड़ा जाता है?
संक्षेप में , उन्हें जोड़ा जा रहा है, क्योंकि उनके पास Detached
राज्य है।
कोड की लाइन निष्पादित करने के बाद
var a = db.Set<A>().Single();
इकाई के बनाए गए उदाहरणों में B
राज्य होता है Detached
। इसे अगले कोड का उपयोग करके सत्यापित किया जा सकता है:
Console.WriteLine(db.Entry(a.S[0]).State);
Console.WriteLine(db.Entry(a.S[1]).State);
फिर जब आप सेट करें
db.Entry(a).Collection(x => x.S).IsModified = true;
ईएफ B
ट्रैकिंग बदलने के लिए संस्थाओं को जोड़ने की कोशिश करता है । EFCore के स्रोत कोड से आप देख सकते हैं कि यह हमें तरीके से ले जाता है InternalEntityEntry.SetPropertyModified अगले तर्क मानों के साथ:
property
- हमारी एक B
संस्था,
changeState = true
,
isModified = true
,
isConceptualNull = false
,
acceptChanges = true
।
इस तरह के तर्कों के साथ इस पद्धति में Detached
B
प्रवेश की स्थिति बदल जाती है Modified
, और फिर उनके लिए ट्रैकिंग शुरू करने की कोशिश की जाती है (देखें लाइनें 490 - 506)। क्योंकि B
संस्थाओं के पास अब यह स्थिति Modified
है कि वे संलग्न (जोड़े नहीं) जाते हैं।