2013-10-08 7 views
8

सी # | .NET 4.5 | इकाई की रूपरेखा 5सभी बच्चों को एक सूची में प्राप्त करें - रिकर्सिव सी #

मैं इकाई की रूपरेखा में एक वर्ग है कि इस तरह दिखता है:

public class Location 
{ 
    public long ID {get;set;} 
    public long ParentID {get;set;} 
    public List<Location> Children {get;set;} 
} 

आईडी स्थान की पहचान करने की ParentID एक माता पिता के लिए यह लिंक है, और बच्चे के बच्चों के सभी स्थानों को शामिल अभिभावक स्थान। मैं सभी "स्थान" और उनके बच्चों को एक ही सूची में स्थान.आईडी युक्त रखने के लिए, संभवतः दोबारा आसान तरीके की तलाश कर रहा हूं। मुझे इस पुनरावर्ती अवधारणा में परेशानी हो रही है। किसी भी मदद की सराहना की है।

यह वही है मैं अब तक इकाई वर्ग के लिए अपनी एक विस्तार है, है, लेकिन मेरा मानना ​​है कि यह किया जा सकता है बेहतर/आसान:

public List<Location> GetAllDescendants() 
{ 
    List<Location> returnList = new List<Location>(); 
    List<Location> result = new List<Location>(); 
    result.AddRange(GetAllDescendants(this, returnList)); 
    return result; 
} 

public List<Location> GetAllDescendants(Location oID, ICollection<Location> list) 
{ 
    list.Add(oID); 
    foreach (Location o in oID.Children) 
    { 
      if (o.ID != oID.ID) 
        GetAllDescendants(o, list); 
    } 
    return list.ToList(); 
} 

UPDATED

मैं लिख रहा समाप्त हो गया एसक्यूएल में रिकर्सन, एसपी में फेंकना, और फिर इसे एंटिटी में खींचना। लिंक्स का उपयोग करने के मुकाबले मुझे साफ और आसान माना जाता है, और टिप्पणियों के आधार पर लिंक और एंटिटी जाने का सबसे अच्छा मार्ग नहीं लगता है। सारी मदद के लिए धन्यवाद!

+0

इकाई फ्रेमवर्क में पुनरावर्ती प्रश्नों के साथ कुछ भी शामिल नहीं है। – Aron

+0

हां, मैं इस कार्यक्षमता को विस्तारित करना चाहता था, मेरे संपादन देखें। – Will

+0

मुझे लगता है कि आप इकाई फ्रेमवर्क आलसी लोडिंग द्वारा समर्थित लिंक टू ऑब्जेक्ट सॉल्यूशन के बजाय एक इकाई फ्रेमवर्क समाधान चाहते थे ... मैंने इकाई फ्रेमवर्क 6 स्रोत कोड में देखा और वास्तव में कार्यक्षमता को जोड़ना चाहता था ...हालांकि माइक्रोसॉफ्ट ने अवशेष वर्गों को 'आंतरिक' के रूप में सेट किया। बीएएस $%^डीएस – Aron

उत्तर

10

आप क्या कर सकते हैं SelectMany

List<Location> result = myLocationList.SelectMany(x => x.Children).ToList(); 

आप की तरह

List<Location> result = myLocationList.Where(y => y.ParentID == someValue) 
             .SelectMany(x => x.Children).ToList(); 

कुछ चुनिंदा परिणामों के लिए जहां हालत उपयोग कर सकते हैं आप केवल आवश्यक ईद बच्चे के मान लीजिए कि आप यह मानते हुए

List<long> idResult = myLocationList.SelectMany(x => x.Children) 
            .SelectMany(x => x.ID).ToList(); 
+1

यह कई स्तरों के माध्यम से पार हो जाएगा। कहें कि किसी स्थान में बच्चे हैं, और उन बच्चों के बच्चे हैं? – Will

+0

+1 यह सिज़मोन के उत्तर से बेहतर है, और संभव है कि आप किसी भी डेटाबेस संरचना के बिना बॉक्स के बाहर ईएफ के साथ सबसे अच्छा हो। हालांकि आप अभी भी ओ (स्तर) डेटाबेस कॉल कर रहे होंगे। – Aron

+0

क्या यह शायद रिकर्सिव एसक्यूएल के रूप में लिखना बेहतर होगा और इसे संग्रहीत प्रक्रिया में रखेगा? मैं वास्तव में केवल आईडी की तलाश में हूं, पूरी संस्था वस्तु के साथ वास्तव में चिंतित नहीं हूं। – Will

0

कर सकते हैं Locations आपके डीबी cont में DbSet<Location> है ext, यह आपकी समस्या का समाधान करेगा "मैं कुछ आसान तरीका ढूंढ रहा हूं ... सभी 'स्थान' और उनके बच्चों को एक ही सूची में स्थान.आईडी के" "प्राप्त करने के लिए। ऐसा लगता है कि मुझे कुछ याद आ रहा है, इसलिए अगर ऐसा है तो कृपया स्पष्टीकरण दें।

dbContext.Locations.ToList() 
// IDs only would be dbContext.Locations.Select(l => l.ID).ToList() 
+0

पूरे डेटाबेस को पकड़ो, काम करेगा ... sorta। – Aron

+0

उद्धृत के रूप में अपने प्रश्न के आधार पर, यह वास्तव में काम करता है ... – Moho

4

इकाई की रूपरेखा वर्तमान में प्रत्यावर्तन का समर्थन नहीं करता है, और उस कारण के लिए आप या तो

  • आलसी लोड हो रहा है बच्चे के संग्रह पर भरोसा कर सकते के रूप में किया है (N + 1 समस्या सावधान रहना)
  • क्वेरी वस्तुओं की एक मनमाना गहराई (यह एक बदसूरत पूछताछ हो पाएंगे, लेकिन आप System.Linq.Expressions का उपयोग कर इसे उत्पन्न कर सकता है)

केवल वास्तविक विकल्प का उपयोग कर से बचने के लिए किया जाएगा LINQ क्वेरी व्यक्त करने के लिए, और इसके बजाय मानक एसक्यूएल का सहारा लेना।

इकाई ढांचा इस परिदृश्य का समर्थन करता है कि आप पहले कोड का उपयोग कर रहे हैं या नहीं।

कोड-प्रथम के लिए, के लिए, मॉडल-पहले

var results = this.db.Database.SqlQuery<ResultType>(rawSqlQuery) 

की तर्ज पर कुछ विचार करना एक defining query जो मुझे लगता है के रूप में यह आगे रचना, या संग्रहित प्रक्रियाओं की अनुमति देता है एक अच्छा विकल्प है प्रयोग करने पर विचार।

रिकर्सिवली डेटा वापस पाने के लिए आपको आप एसक्यूएल सर्वर का उपयोग कर रहे संभालने पुनरावर्ती सीटीई को समझने की जरूरत है, और यह संस्करण 2005+ है कि

संपादित करें:

यहाँ एक पुनरावर्ती पूछताछ के लिए कोड है एक मनमानी गहराई के लिए। मैंने इसे मस्ती के लिए एक साथ रखा, मुझे संदेह है कि यह बहुत ही कुशल होगा!

var maxDepth = 5; 

var query = context.Locations.Where(o => o.ID == 1); 
var nextLevelQuery = query; 

for (var i = 0; i < maxDepth; i++) 
{ 
    nextLevelQuery = nextLevelQuery.SelectMany(o => o.Children); 
    query = query.Concat(nextLevelQuery); 
} 

चपटी सूची चर क्वेरी

+0

यही वह है जो मैंने किया। सहायता के लिए धन्यवाद। – Will

11

में है इस विस्तार विधि का प्रयास करें:

public static IEnumerable<T> Flatten<T, R>(this IEnumerable<T> source, Func<T, R> recursion) where R : IEnumerable<T> 
{ 
    return source.SelectMany(x => (recursion(x) != null && recursion(x).Any()) ? recursion(x).Flatten(recursion) : null) 
       .Where(x => x != null); 
} 

और तुम इस तरह इसका इस्तेमाल कर सकते हैं:

locationList.Flatten(x => x.Children).Select(x => x.ID); 
+0

जिस तरह से कोड लिखा गया है, आपको 'आर' जेनेरिक पैरामीटर की आवश्यकता नहीं है। – GreatAndPowerfulOz

3

मैं चाहते हैं मेरा स्वयं का समाधान योगदान दें, जिसे नीचे दिए गए संदर्भों से संशोधित किया गया था:

public static IEnumerable<T> Flatten<T, R>(this IEnumerable<T> source, Func<T, R> recursion) where R : IEnumerable<T> 
{ 
    var flattened = source.ToList(); 

    var children = source.Select(recursion); 

    if (children != null) 
    { 
     foreach (var child in children) 
     { 
      flattened.AddRange(child.Flatten(recursion)); 
     } 
    } 

    return flattened; 
} 

उदाहरण:

var n = new List<FamilyMember>() 
{ 
    new FamilyMember { Name = "Dominic", Children = new List<FamilyMember>() 
     { 
      new FamilyMember { Name = "Brittany", Children = new List<FamilyMember>() } 
     } 
    } 
}.Flatten(x => x.Children).Select(x => x.Name); 

आउटपुट:

  • डोमिनिक
  • ब्रिटनी

कक्षा:

public class FamilyMember { 
    public string Name {get; set;} 
    public List<FamilyMember> Children { get; set;} 
} 

रेफरी। https://stackoverflow.com/a/21054096/1477388

नोट: अन्य संदर्भ नहीं मिल रहा है, लेकिन एसओ पर किसी और ने एक उत्तर प्रकाशित किया है कि मैंने कुछ कोड कॉपी किया है।

+0

जिस तरह से कोड लिखा गया है, आपको 'आर' जेनेरिक पैरामीटर की आवश्यकता नहीं है। – GreatAndPowerfulOz

3

इस चाल करना होगा:

class Extensions 
{ 
    public static IEnumerable<T> SelectManyRecursive<T>(this IEnumerable<T> source, Func<T, IEnumerable<T>> selector) 
    { 
     var result = source.SelectMany(selector); 
     if (!result.Any()) 
     { 
      return result; 
     } 
     return result.Concat(result.SelectManyRecursive(selector)); 
    } 
} 

इस तरह यह प्रयोग करें:

List<Location> locations = new List<Location>(); 
// 
// your code here to get locations 
// 
List<string> IDs = locations.SelectManyRecursive(l => l.Children).Select(l => l.ID).ToList(); 
+1

यदि आप डाउनवोट करने जा रहे हैं, कम से कम यह कहने की सौजन्य है कि क्यों। – GreatAndPowerfulOz

+0

मेरे लिए काम किया .. धन्यवाद –

1

मैं अपने मॉडल में कोई Children प्रोप थी, इसलिए निखिल अग्रवाल के जवाब काम नहीं करता है मेरे लिए, तो मेरा समाधान यहाँ है।

निम्नलिखित मॉडल के साथ

:

public class Foo 
{ 
    public int Id { get; set; } 
    public int? ParentId { get; set; } 
    // other props 
} 

आप एक आइटम के बच्चों का उपयोग कर प्राप्त कर सकते हैं:

List<Foo> GetChildren(List<Foo> foos, int id) 
{ 
    return foos 
     .Where(x => x.ParentId == id) 
     .Union(foos.Where(x => x.ParentId == id) 
      .SelectMany(y => GetChildren(foos, y.Id)) 
     ).ToList(); 
} 

पूर्व के लिए।

List<Foo> foos = new List<Foo>(); 

foos.Add(new Foo { Id = 1 }); 
foos.Add(new Foo { Id = 2, ParentId = 1 }); 
foos.Add(new Foo { Id = 3, ParentId = 2 }); 
foos.Add(new Foo { Id = 4 }); 

GetChild(foos, 1).Dump(); // will give you 2 and 3 (ids) 
संबंधित मुद्दे