2016-10-16 5 views
0

Scheint so, als ob das schon beantwortet worden wäre, aber ich kann es nicht finden.
ich folgenden Tabelle haben:Wie man Selbstreferenzierungsanfrage abflachen?

Id  Parent  Text 
----------------------- 
1  NULL  A 
2  1   B 
3  2   C 
4  3   D 
5  NULL  E 
6  5   F 
7  6   G 

Jetzt möchte ich so das Ergebnis haben: (List<string>)

A 
A > B 
A > B > C 
A > B > C > D 
E 
E > F 
E > F > G 

Aber das Problem ist, dass dieses Projekt, das ich auf sie arbeite, Anwendungen Datenbank zuerst, ich meine, es gibt keine Navigationseigenschaft, Parent ist Typ von string nicht IEnumerable<T>.

Was ich bisher getan haben:

var list = new List<string>(); 
string e2 = string.Empty; 
foreach (var item in query) 
{ 
    string e1 = string.Empty; 
    if (item.Parent == null) 
    { 
     list.Add(p.Text); 
     e2 = item.Text; 
    } 
    else 
    { 
     foreach (var subItem in query.Where(t => t.Id == p.Parent)) 
     { 
      if (subItem.Id != 1) 
      { 
       e1 = e2 + " > " + subItem.Text; 
      } 
      else 
      { 
       e1 = subItem.Text; 
      } 
     } 
     list.Add(e1 + " > " + p.Text); 
    } 
} 
+0

zeigen die Definition der 'query' Variable –

+0

es ist nur eine einfache Linq-Abfrage:' var query = von Posten in myTable \t \t \t wählen Sie den Punkt; ' –

+1

Es gibt einen großen Unterschied, ob die Abfrage' IQueryable ist 'oder' IEnumerable '. Im ersten Fall führen Sie N Datenbankabfragen durch. Im zweiten Fall wird der naive Algorithmus, den Sie akzeptiert haben, N * N Suchen durchführen. Mit anderen Worten, beide werden sehr ineffizient sein. Wie auch immer, das Problem liegt ganz bei dir :) –

Antwort

1

Verwendung rekursiven Algorithmus

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Data; 

namespace ConsoleApplication1 
{ 
    class Program 
    { 
     static List<string> list = new List<string>(); 
     static DataTable dt = new DataTable(); 
     static void Main(string[] args) 
     { 
      dt.Columns.Add("Id", typeof(int)); 
      dt.Columns.Add("Parent", typeof(int)); 
      dt.Columns["Parent"].AllowDBNull = true; 
      dt.Columns.Add("Text", typeof(string)); 

      dt.Rows.Add(new object[] {1, null, "A"}); 
      dt.Rows.Add(new object[] {2, 1, "B"}); 
      dt.Rows.Add(new object[] {3, 2, "C"}); 
      dt.Rows.Add(new object[] {4, 3, "D"}); 
      dt.Rows.Add(new object[] {5, null, "E"}); 
      dt.Rows.Add(new object[] {6, 5, "F"}); 
      dt.Rows.Add(new object[] {7, 6, "G"}); 

      GetRecursiveChildren(null, new List<string>()); 

      foreach (string row in list) 
      { 
       Console.WriteLine(row); 
      } 
      Console.ReadLine(); 
     } 
     static void GetRecursiveChildren(int? parent, List<string> parents) 
     { 
      foreach (DataRow row in dt.AsEnumerable().Where(x => x.Field<int?>("Parent") == parent)) 
      { 
       string text = row.Field<string>("Text"); 
       List<string> newParents = new List<string>(); 
       newParents.AddRange(parents); 
       newParents.Add(text); 
       list.Add(string.Join(" > ",newParents)); 
       int child = row.Field<int>("Id"); 
       GetRecursiveChildren(child, newParents); 
      } 
     } 
    } 

} 
1

Dies funktioniert für mich:

var source = new [] 
{ 
    new { Id = 1, Parent = (int?)null, Text = "A" }, 
    new { Id = 2, Parent = (int?)1, Text = "B" }, 
    new { Id = 3, Parent = (int?)2, Text = "C" }, 
    new { Id = 4, Parent = (int?)3, Text = "D" }, 
    new { Id = 5, Parent = (int?)null, Text = "E" }, 
    new { Id = 6, Parent = (int?)5, Text = "F" }, 
    new { Id = 7, Parent = (int?)6, Text = "G" } 
}; 

var lookup = source.ToLookup(x => x.Parent); 

Func<int?, IEnumerable<string>> recurse = null; 
recurse = p => 
    lookup[p].SelectMany(x => new [] { x.Text } 
     .Concat(recurse(x.Id).Select(y => $"{x.Text} > {y}"))); 

foreach (string x in recurse(null)) 
{ 
    Console.WriteLine(x); 
} 

ich:

 
A 
A > B 
A > B > C 
A > B > C > D 
E 
E > F 
E > F > G