2017-02-11 3 views
1

Baumtiefe ich die folgenden selbst verweisende Tabelle für ein Kind categroy, sagenstring.split in Einheit mit

public partial class products_category 
    { 
    public long id { get; set; } 
    public string category_name { get; set; } 
    public string category_description { get; set; } 
    //self referencing to table id 
    public Nullable<long> Parent_Id { get; set; } 
    public string navPath {get; set; } 
} 

hier String navpath enthält alle führend Eltern zu durchqueren:

"Clothes" = 1 Parent_id=null, navpath="" 
"Silk" = 2 Parent_id=1 navpath="1" 
"Silk Suit"=3 parent_id=2 navpath="1-2" 
"Saree" =4 parent_id=3 navpath="1-2-3" 
"Dress Material"=5 parent_id=1 navpath="1" and so on.... 

Nun möchte ich gemäß diesem Szenario auf den Flattend-Baum für weitere Verarbeitung für eine bestimmte Tiefe nur sagen, Ebene 2 oder bis Ebene 4 Tiefe der Kinder mit Navpath verbunden.

meine Idee dieses Problem in Bezug war mit Linq auf diese Weise zu nähern ef:

var catTrees = db.products_category.Where(pc => pc.navpath.Split('-').Length < 4).ToList(); 

i den folgenden Link bin mit weiterer Verfahrgeschwindigkeit und Baum Generation zu tun: https://bitlush.com/blog/recursive-hierarchical-joins-in-c-sharp-and-linq

und es tut Eine großartige Arbeit bis jetzt, das einzige Problem ist, dass ich nicht die gesamte Tabelle für die Verarbeitung vorwählen möchte. Ich möchte Paging und ein gewisses Maß an Tiefe für die erste Iteration erreichen, so dass ich die Leistung im Falle von tausend von Aufzeichnungen aufrechterhalten kann. [Betrachten Sie dies als Kategoriehierarchie oder Blog-/Youtube-Kommentarhierarchie].

aber den oben ef Linq Befehl gibt den folgenden Fehler:

The LINQ expression node type 'ArrayLength' is not supported in LINQ to Entities. 

i mit ef-Dokumenten und anderen Orten in SO vergewisserte, dass string.split zu wissen implizit mit EF nicht funktioniert. aber können wir es mit Erweiterungsmethoden anwenden, oder kann diese Baumauswahl einen alternativen Ansatz haben, ohne string.split zu verwenden und nur DBs zu treffen? bitte beraten.

Antwort

1

Dies sieht aus wie ein Problem beim Erstellen von SQL-Code aus Ihrem LINQ mpre speziell SQL, die eine Zeichenfolge nimmt teilt es auf Bindestrich und zählt die Elemente.

wenn Sie die Idee des Ladens in den Speicher nicht hassen, dann können Sie etwas zwingen :)

var catTrees = db.products_category.ToList().Where(pc => pc.navpath.Split('-').Length < 4).ToList(); 

Der Trick hier ist die Ausführung des SQL zu erzwingen, indem die .ToList() hinzuzufügen, wenn wir die Daten aus den wollen Datenbank. Dies wird als Realisieren der Daten bezeichnet.

Auch bei dieser Erkenntnis Trick ist, die Zählung schneller

var catTrees = db.products_category.ToList().Where(pc => pc.navpath.Count(a => a == '-') < 3).ToList(); 

diese Lösungen im Wesentlichen die gleichen sind wie

List<Result> filter() { 
    List<Result> r = new List<Result>(); 
    foreach(var a in db.products_category) { 
     if(a.navpath.Count(a => a == '-') < 3) { 
      r.add(a); 
     } 
    } 
    return r; 
} 

Wenn darüber nachzudenken die Filtermethode etwas weniger speicherintensiv ist, wie es liest und eins und speichert nie alles in Erinnerung. (In der Theorie wissen nur wenige wirklich, was der .NET-Compiler in den Schatten tut)

+0

Überprüfung Ihren Vorschlag – Alok

+0

kein Glück DbExpressionBinding erfordert einen Eingangsausdruck mit einer Sammlung Result. – Alok

+0

ok, war einen Schuss wert ,. Aber hier ist eine Lösung, die immer funktioniert. –

0

Ich würde Sie gegen die Verwendung der navpath zur Überprüfung der Tiefe empfehlen.

Wenn Sie Ihr Modell ändern können, könnten Sie ein zusätzliches numerisches Depth Feld für jede Kategorie hinzufügen und füllen sie sich nach navpath, dann könnte man sich aus dem Code auf diese Weise wählen:

var catTrees = db.products_category.Where(pc => pc.Depth < 3).ToList(); 

Es gibt Es gibt viele Möglichkeiten, diese neue Spalte zu füllen, aber die Quintessenz ist, dass Sie dies nur einmal tun müssen (vorausgesetzt, dass Sie jedes Mal, wenn Sie die navpath einer Kategorie ändern, den Überblick behalten).

Eine Möglichkeit, es zu bevölkern würde durch alle Kategorien werden Looping, so etwas wie:

var allCategories = db.products_category.ToList(); 
foreach(var category in allCategories) 
{ 
    var depth = category.navpath == "" ? 0 : category.navpath.Split('-').Length + 1; 
    category.Depth = depth; 
} 
allCategories.SubmitChanges(); 
Verwandte Themen