2013-05-20 3 views
39

ठीक है, मेरे पास है एक-से-कई संबंधित मॉडल:ईएफ कोड पहले डेटाबेस में कई संबंधित रिकॉर्ड में बच्चे को कैसे हटाएं?

public class Parent 
{ 
    public int Id { get; set; } 
    public string Name { get; set; } 
    public ICollection<Child> Children { get; set; } 
} 

public class Child 
{ 
    public int Id { get; set; } 
    public string ChildName { get; set; } 
} 

मुझे क्या करना चाहते हैं स्पष्ट Parent.Children है और डेटाबेस से संबंधित बच्चे संस्थाओं को हटा दें। मैं पहले से ही की कोशिश की है:

डाटाबेस संदर्भ वर्ग:

modelBuilder.Entity<Parent>() 
      .HasMany(p => p.Children) 
      .WithOptional() 
      .WillCascadeOnDelete(true); 

इस ठीक काम करता है, लेकिन मैं अभी भी Parent_Id = null क्षेत्रों जब मैं

parent.Children.Clear(); 
repository.InsertOrUpdate(parent); 

कर में साथ डेटाबेस में अनावश्यक रिकॉर्ड मेरी भंडार वर्ग। इसके अलावा एक ही व्यवहार जब मैं क्या है:

modelBuilder.Entity<Parent>() 
      .HasMany(pr => pr.Children) 
      .WithOptional(ri => ri.Parent) 
      .WillCascadeOnDelete(true); 
अतिरिक्त Parent संपत्ति के साथ

Child

public class Child 
{ 
    ... 
    public Parent Parent { get; set; } 
    ... 
} 

में कक्षा या जब मैं Child कक्षा में अतिरिक्त PARENT_ID संपत्ति के साथ

modelBuilder.Entity<Child>() 
      .HasOptional(p => p.Parent) 
      .WithMany(p => p.Children) 
      .HasForeignKey(p => p.Parent_Id) 
      .WillCascadeOnDelete(true); 

कर

public class Child 
{ 
    ... 
    public int Parent_Id { get; set; } 
    ... 
} 

तो, मैं सही ढंग से कैस्केड हटाने को कैसे कॉन्फ़िगर कर सकता हूं? या मुझे उन बच्चों की संस्थाओं को कैसे हटाया जाना चाहिए? मुझे लगता है कि यह अनौपचारिक काम है लेकिन मुझे बस कुछ याद आ रहा है।

+0

क्या आप कुछ और कोड पोस्ट कर सकते हैं? हो सकता है कि आपके 'ऑनमोडेल क्रिएटिंग() 'की पूरी सामग्री? जब मैं आपकी संस्थाओं और आपके पहले मैपिंग प्रयास को कॉपी और पेस्ट करता हूं (और दोनों आईडी के लिए मुख्य संपत्ति के रूप में 'आईडी' सेट करता हूं), तो मेरे लिए सही ढंग से कैस्केडिंग कर रहे हैं। –

उत्तर

37

व्यापक हटाना यहाँ कोई प्रभाव नहीं है क्योंकि आप parent हटाना नहीं है, लेकिन सिर्फ InsertOrUpdate फोन अपने parent.Children.clear काम कर नहीं है।

using (var context = new MyContext()) 
{ 
    var parent = context.Parents.Include(p => p.Children) 
     .SingleOrDefault(p => p.Id == parentId); 

    foreach (var child in parent.Children.ToList()) 
     context.Children.Remove(child); 

    context.SaveChanges(); 
} 
+0

निश्चित रूप से आप पर कैस्केड हटाने के साथ बच्चों को व्यक्तिगत रूप से हटाने की जरूरत नहीं है? –

+5

@kirsteng: कैस्केडिंग डिलीट का मतलब है कि बच्चे हटा दिए जाते हैं ** यदि ** आप माता-पिता को हटा देते हैं।लेकिन इस सवाल में कोई अभिभावक हटा नहीं गया है। इसलिए, कैस्केडिंग डिलीट इस परिदृश्य पर लागू नहीं होता है। – Slauma

+8

सभी "बच्चे" ऑब्जेक्ट्स का प्रचार करने के बजाय, बस 'context.Children.RemoveRange (parent.Children.ToArray()) कहें' जिस तरह से डीबीकॉन्टेक्स्ट को हर बार जब आप कॉल करते हैं तो अधिक काम करने की ज़रूरत नहीं होती है। यह हटाए जाने के लिए एक बड़ी प्रदर्शन समस्या नहीं हो सकती है, लेकिन मैंने एक समय में आइटम जोड़ने पर एक बड़ा अंतर देखा है जब मैंने 'संदर्भ के लिए 100k रिकॉर्ड्स जोड़ने का परीक्षण किया था। बच्चे। जोड़ें (बच्चे)' लूप में। – matrixugly

3

कोशिश

public virtual ICollection<Child> Children { get; set; } 

के लिए बदल रहा है क्योंकि आभासी आलसी लोड हो रहा है पाने के लिए की जरूरत है। के रूप में समझाया here

मुझे लगता है कि क्योंकि बच्चे लोड नहीं किया गया है

86

EF6 में ऑपरेशन है क्या करने के लिए एक तेज़ तरीका ...

context.Children.RemoveRange(parent.Children) 
+0

यह कोड का एक तेज़ तरीका है लेकिन प्रदर्शन के संदर्भ में, क्या यह वास्तव में तेज़ है? अगर मैं माता-पिता के तहत सभी माता-पिता को 'parent.Id == 10'' से हटा देना चाहता हूं, और मेरे 'चाइल्ड' क्लास में 100 फ़ील्ड हैं और अभी तक स्मृति में लोड नहीं हुए हैं, तो यह' RemoveRange' का उपयोग करने में अक्षम है क्योंकि प्रोग्राम के पास होगा डिफ़ॉल्ट रूप से सभी 100 फ़ील्ड के साथ 'parent.Children' लोड करने के लिए। – VCD

+0

@VCD यह संदर्भ कॉल करने से तेज़ है। बच्चे। प्रत्येक बच्चे के लिए निकालें (बच्चे) लेकिन एसक्यूएल चलाने के जितना तेज़ नहीं है "बच्चों से हटाएं जहां parentId = @ parentId" –

+0

माता-पिता को ढूंढने के बारे में आप कैसे जाएंगे, अगर केवल एक ही जानकारी क्या बच्चा आईडी है? – guyfromfargo

0

अपने वस्तु है: सही प्रक्रिया उदाहरण के लिए तो जैसे बच्चों को एक-एक करके नष्ट करने के लिए, है आत्म-संदर्भ, आप नीचे दी गई विधि का उपयोग करके कई से कई और एक से अधिक बच्चों को हटा सकते हैं। बस db.SaveChanges() को बाद में कॉल करना याद रखें :)

[HttpPost, ActionName("Delete")] 
[ValidateAntiForgeryToken] 
public ActionResult DeleteConfirmed(int id) 
{ 
    Object obj = this.db.Objects.Find(id); 
    this.DeleteObjectAndChildren(obj); 
    this.db.Objects.Remove(obj); 
    this.db.SaveChanges(); 
    return this.Json(new { success = true }); 
} 

/// <summary> 
/// This deletes an object and all children, but does not commit changes to the db. 
/// - MH @ 2016/08/15 14:42 
/// </summary> 
/// <param name="parent"> 
/// The object. 
/// </param> 
private void DeleteObjectAndChildren(Object parent) 
{ 
    // Deletes One-to-Many Children 
    if (parent.Things != null && parent.Things.Count > 0) 
    { 
     this.db.Things.RemoveRange(parent.Things); 
    } 

    // Deletes Self Referenced Children 
    if (parent.Children != null && parent.Children.Count > 0) 
    { 
     foreach (var child in parent.Children) 
     { 
      this.DeleteObjectAndChildren(child); 
     } 

     this.db.Objects.RemoveRange(parent.Children); 
    } 
} 
संबंधित मुद्दे