2013-01-31 8 views
9

मैं अपने बालों को लगभग 2 दिनों के लिए खींच रहा हूं, क्योंकि जब भी मैं कई-से जोड़ता हूं तो मैं परिवर्तनों को सहेजने के लिए ईएफ नहीं प्राप्त कर सकता एक मौजूदा इकाई के लिए कई इकाई।एंटिटी फ्रेमवर्क 6 में कई से अधिक नेविगेशन प्रॉपर्टी अपडेट करना, सहेजे नहीं जा रहे परिवर्तन

मेरे संरचना सादा सरल है:

  • मैं एक मेज Person कहा जाता है, यह एक आईडी (प्राथमिक, पहचान), और कुछ अन्य स्ट्रिंग क्षेत्रों

  • एक मेज के साथ Keyword कहा जाता है एक आईडी (प्राथमिक, पहचान) और एक स्ट्रिंग क्षेत्र, Value

  • और एक PersonKeywordRelation नामक एक PersonId साथ, और एक KeywordId क्षेत्र

जब मैं अपने संस्थाओं (डाटाबेस पहले), मैं एक वर्ग Person, एक ICollection<Keyword> साथ मिल जेनरेट किया है - सब अच्छा है, के रूप में उम्मीद काम करता है।

समस्या तब उत्पन्न होती है जब मैं मौजूदा Person को कीवर्ड की संशोधित सूची सहेजने का प्रयास करता हूं। केवल स्केलर गुण (तार) सहेजे गए हैं, मेरे कीवर्ड नहीं!

  • मैंने आलसी लोडिंग को अक्षम करने का प्रयास किया है, कोई प्रभाव नहीं।
  • मैंने डेटाबेस से प्रत्येक अलग-अलग कीवर्ड को फिर से लोड करने का प्रयास किया, कोई प्रभाव नहीं।
  • मैंने संदर्भ में सभी कीवर्ड लोड करने का प्रयास किया ताकि यह देखने के लिए कि क्या ईएफ परिवर्तनों का पता लगाने में मदद करेगा, ऐसा नहीं हुआ।

मुझे पूरा यकीन है कि मैं अकेला नहीं हूं जिसने यह समस्या है, (वास्तव में मुझे पूरी तरह से यकीन है क्योंकि मैंने पहले से ही एक ही विषय पर कुछ प्रश्न देखे हैं, फिर भी मैं असमर्थ हूं एक कामकाजी उत्तर खोजने के लिए ...), ज्यादातर ईएफ के पुराने संस्करणों के लिए, जो एक और अच्छा कारण है कि मैंने अभी तक एक और सवाल क्यों शुरू किया: क्या इस मुद्दे को हल करने में कुछ भी नहीं बदला है?

यहां मेरा कोड है जो व्यक्तियों के अद्यतन (और निर्माण) करता है। आप ईएफ को तदनुसार परिवर्तनों को सहेजने पर अपना प्रयास देखेंगे।

public void SavePersons(IList<Person> persons) 
    { 
     // Create a EF Context 
     using (var ctx = new MyDbEntities()) 
     { 
      foreach (var person in persons) 
      { 
       // Attach 
       ctx.Persons.Attach(person); 

       // Insert or update? 
       ctx.Entry(person).State = person.Id == 0 ? EntityState.Added : EntityState.Modified; 

       // Get current keywords before clearing from entity 
       var keywords = new List<Keyword>(person.Keywords); 

       // Clear keywords from entity, so we can add fresh ones, hopefully 
       // EF will have an easier time handling this.. 
       person.Keywords.Clear(); 

       // Add keywords 
       keywords.ForEach(kw => 
       { 
        ctx.Keywords.Attach(kw); 
        ctx.Entry(kw).State = EntityState.Modified; 
        person.Keywords.Add(kw); 
       });    
      } 

      // Save 
      ctx.SaveChanges(); 
     } 
    } 
+0

क्या आपके कीवर्ड के मूल्य बदल रहे हैं या व्यक्ति और कीवर्ड के बीच संबंध बदल रहे हैं या दोनों? –

+0

केवल रिश्ते - हालांकि दोनों को समर्थित होना चाहिए, अधिमानतः। – Jeff

उत्तर

11

अंत में .. अंत में मैं आराम कर सकते हैं! मुझे समाधान मिला! यह एक सुंदर नहीं है, लेकिन यह काम करता है!

यहां कोड - साझाकरण की देखभाल है।

यह निश्चित रूप से आखिरी बार है जब मैं एंटिटी फ्रेमवर्क के साथ काम करूंगा। अच्छे से अधिक दर्द & पीड़ा का कारण बनता है।

public void SavePersons(IList<Person> persons) 
    { 
     // Create a EF Context 
     using (var ctx = new MyDbEntities()) 
     { 
      // Iterate 
      foreach (var person in persons) 
      { 
       // Get current keywords 
       var keywords = new List<Keyword>(person.Keywords).ToList(); 

       // Fetch Person from DB (if its not a NEW entry). Must use Include, else it's not working. 
       var newPerson = ctx.Persons 
             .Include("Keywords") 
             .FirstOrDefault(s => s.Id == person.Id) ?? person; 

       // Clear keywords of the object, else EF will INSERT them.. Silly. 
       newPerson.Keywords.Clear(); 

       // Insert or update? 
       ctx.Entry(newPerson).State = newPerson.Id == 0 ? EntityState.Added : EntityState.Modified; 

       // Apply new scalar values 
       if(newPerson.Id != 0) 
       { 
        person.Id = newPerson.Id; 
        ctx.Entry(newPerson).CurrentValues.SetValues(person); 

       } 

       // Iterate through all keywords 
       foreach (var kw in ctx.Keywords) 
       { 
        // If the current kw exists in OUR list, add it 
        // - if not, remove the relation from the DB. 
        if (keywords.Any(k => k.Id == kw.Id)) 
        { 
         //ctx.Entry(kw).State = EntityState.Unchanged; 
         ctx.Keywords.Attach(kw); 
         newPerson.Keywords.Add(kw); 
        } 
        else 
         newPerson.Keywords.Remove(kw); 
       } 
      } 

      // Save 
      ctx.SaveChanges(); 

     } 
    } 
+1

इससे मेरी मदद मिली, इसलिए आपका समाधान पोस्ट करने के लिए धन्यवाद। कुंजी लाने के दौरान कुंजी 'शामिल' का उपयोग कर रही थी। मुझे लगा कि नेविगेशन संपत्ति को ट्रैक न करने वाले संदर्भ के साथ मेरी समस्या का कुछ संबंध था। मैं आलसी लोडिंग को अक्षम नहीं करना चाहता था क्योंकि इससे डीटीओ को इकाई मैप करते समय मुझे समस्याएं होती थीं। – chrisjsherm

+0

मुझे इसे समझने में काफी समय लगा, मैंने इस प्रश्न का उत्तर कई बार पोस्ट किया है, जिसे मुझे तब निकालना पड़ा क्योंकि आगे परीक्षण ने बग का खुलासा किया। – Jeff

+0

यहां एक सामान्य संस्करण http://goo.gl/2sCky को कोड करने के तरीके पर स्टैक ओवरफ्लो पर एक समान प्रश्न है –

2

.ToList (जोड़ने का प्रयास करें):

var keywords = new List<Keyword>(person.Keywords).ToList();//generate list sepereate from .Keywords 

मैं शक कर रहा हूँ कि आपके कीवर्ड सूची यह hydrating से पहले क्योंकि आप स्पष्ट यह आबादी वाले कभी नहीं किया गया है।

+0

कोड ब्लॉक के अंदर ** बोल्ड ** मार्कअप का उपयोग नहीं कर सकता, तारों को हटा दिया गया और टिप्पणी – AaronLS

+0

के साथ प्रतिस्थापित किया गया यह ऐसा नहीं किया:/ – Jeff

1

तो निम्नलिखित अनचाहे है लेकिन के बाद आप मेरी बग ठीक करें;) यह उम्मीद है कि यह चाल चलनी चाहिए। मुझे आपके शेष कोड को नहीं पता है इसलिए मैंने इनपुट डेटा के क्लोन बनाने और ऑब्जेक्ट को किसी विशिष्ट क्रम में संदर्भ में जोड़ने का विकल्प चुना है।

संपादित करें: नाम बदलकर विधि

// get unique list of Keywords from all Persons 
    private List<Keyword> getUniqueKeywords(IEnumerable<Person> oxygenThiefs) { 
     var result = new List<Keyword>(); 

     foreach (var thief in oxygenThiefs) { 
      foreach (var keyword in thief.Keywords) { 
       if (!result.Contains(keyword)) { 
        result.Add(keyword); 
       } 
      } 
     } 

     return result; 
    } 

    // shallow clone of Person 
    private Person clonePerson(Person target) { 

     return new Person { 
      Id = target.Id, 
      Name = target.Name, 
      .. 
      .. 

     }; 
    } 

    public void SavePersons(IList<Person> persons) { 
     // Create a EF Context 
     using (var ctx = new MyDbEntities()) { 

      // add all Keywords to the Context so that they are tracked 
      foreach (var keyword in getUniqueKeywords(persons)) { 
       ctx.Keywords.Attach(keyword); 
       // if value of Keyword has actually changed then uncomment line 
       // ctx.Entry(keyword).State = EntityState.Modified 
      } 

      foreach (var person in persons) { 

       // hehe 
       var shallowPerson = clonePerson(person); 

       // Attach Person 
       ctx.Persons.Attach(shallowPerson); 

       // Establish relationship (however shallow and meaningless) 
       foreach (var keyword in person.Keywords) { 
        shallowPerson.Keywords.Add(keyword); 
       } 

       // Insert or update? 
       ctx.Entry(shallowPerson).State = person.Id == 0 ? EntityState.Added : EntityState.Modified; 

      } 

      // Save 
      ctx.SaveChanges(); 
     } 
    } 
+0

उर, तीसरी टिप्पणी, दुख की बात यह काम नहीं कर रहा था ... मैं बहुत तेज़ था। – Jeff

+0

'IENumerable ऑक्सीजनफिफ्स' के लिए अंगूठे ऊपर। आपने मेरा दिन बना दिया! : डी –

संबंधित मुद्दे