2017-02-11 9 views
1

я таблица следующего автореферентногоиспользования String.split в сущности, чтобы пересечь глубину дерева

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; } 
} 

здесь строка navpath содержит все ведущие родитель для ребенка categroy, говорят:

"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.... 

теперь в соответствии с этим сценарием я хочу получить доступ к дереву flattend для обработки на определенной глубине только для уровня 2 или до уровня 4 глубина детей, связанных с навигацией.

моя идея по этому вопросу должен был подойти с помощью LINQ Е.Ф. таким образом:

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

Я использую следующую ссылку, чтобы сделать дальнейшие перемещения и генерации дерева: https://bitlush.com/blog/recursive-hierarchical-joins-in-c-sharp-and-linq

и делает большая работа до сих пор, единственная проблема: я не хочу, чтобы предварительно выбрать целую таблицу для обработки. Я хочу достичь пейджинга и определенного уровня глубины для первой итерации, поэтому я могу поддерживать производительность в случае тысяч записей. [подумайте об этом как иерархии категорий или иерархии комментариев блога/youtube].

, но с помощью команды выше эф LinQ дает следующее сообщение об ошибке:

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

я проверил с эф документы и в других местах в SO, чтобы знать, что String.split не работает с EF неявно. но можем ли мы применить его с помощью методов расширения или может ли этот выбор дерева иметь альтернативный подход, не используя string.split и удаляя только DB? пожалуйста совет.

ответ

1

Это похоже на проблемы с созданием SQL-кода из вашего LINQ mpre, в частности SQL, который берет строку, разбивая ее на тире и подсчитывая элементы.

если вы не ненавидите идею загрузки в память, то вы можете заставить что-нибудь :)

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

Хитрость здесь, чтобы заставить выполнение SQL, добавив .ToList(), когда мы хотим, чтобы данные из база данных. Это называется реализацией данных.

Даже с этой реализацией трюк граф быстрее

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

эти решения по существу такой же, как

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; 
} 

Размышляя об этом метод фильтра несколько меньше памяти интенсивно, как гласит один и один и никогда не хранит все в памяти. (теоретически, по крайней мере, лишь немногие действительно знают, что компилятор .NET делает в тени)

+0

проверяя ваше предложение – Alok

+0

не повезло DbExpressionBinding не требует ввода выражения с коллекцией ResultType. – Alok

+0

ОК, стоило сделать снимок. но вот решение, которое всегда работает. –

0

Я бы посоветовал вам использовать navpath для проверки глубины.

Если вы можете изменить свою модель, вы можете добавить дополнительный цифровой Depth поле для каждой категории и заполнить его в соответствии его navpath, то вы можете выбрать их из кода таким образом:

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

Есть много способов заполнить этот новый столбец, но в итоге вы должны будете сделать это только один раз (учитывая, что вы отслеживаете его каждый раз, когда вы изменяете navpath категории).

Одним из возможных способов пополнения его будет пробегаем по всем категориям, что-то вроде:

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();