Сценарий
Я построил структуру базы данных, которая представляет дерево категорий, чтобы помочь классифицировать некоторые данные, которые мы сохранили.Реализация состоит в том, что каждая запись в таблице Category
имеет обнуляемый внешний ключ обратно в таблицу Category
для представления родительского элемента Category
этой категории (один-ко-многим), что по существу позволяет использовать подкатегории в более широком родительском элементеуровень.Существует таблица CategoryMembership
, которая связывает запись в таблице Item
с соответствующей ей Category
(многие ко многим).Я создал DBML для этой базы данных, и он имеет структуру доступа к элементам, которая включает следующее:
Dim aCategory As New Category()
Dim aParentCategory As Category = aCategory.Parent
Dim aChildCategoryCollection As EntitySet(Of Category) = aCategory.Subcategories
Dim aMembershipCollection As EntitySet(Of CategoryMembership) = aCategory.CategoryMemberships
Каждый элемент в aMembershipCollection
имеет следующую структуру доступа к элементам:
Dim aMembership As CategoryMembership = aMembershipCollection.First()
Dim aLinkedCategory As Category = aMembership.Category
Dim aLinkedItem As Item = aMembership.Item
Требование
Я пытаюсь создать выражение LINQ, которое позволило бы мне определить, какие Items
имеют CategoryMemberships
для запрошенного Category
(то есть aCategory.id = myID
) или членство для потомков запрошенного Category
, идея в том, что я хочу, чтобы все Items
находились в родительской категории или в ее нескольких уровнях подкатегорий.
По сути, запрос будет построен вмода похожа на:
Dim results As IQueryable(Of Item) = _
From cm In db.CategoryMemberships.Where(myInCategoryPredicate(myID)) _
Select cm.Item
... где myInCategoryPredicate
возвращает объект выражения LINQ, который помог бы мне сделать это определение.Это, конечно, работает исходя из предположения, что таблица CategoryMembership
- это место, откуда нужно начинать извлекать IQueryable(Of Item)
.Возможно, я сделал здесь ошибочное предположение, и именно поэтому я пришел за советом.
Проблема
Мне трудно увидеть лес длядеревья.Я не могу определить, должен ли я начать создавать предикат из категории или из членства в категории, и не могу понять необходимый код, который бы выполнил то, что я хотел бы.Я надеюсь, что кто-то еще, кто уже построил подобную древовидную структуру для базы данных, мог бы помочь мне ориентироваться в классах DBML.
Доступные ресурсы
Ранее я уже использовал PredicateBuilder в прошлом и относительно знаком с его работой, но я не смог придумать способ прохода вверх по дереву и рекурсивного построения предиката, который бы указывалнаходится ли Предмет в категории, которая является или запрошенной категорией, или дочерним элементом.До сих пор я произвел следующее с очень заметным пробелом, помеченным SomeRecursiveCall ():
Private Function InCategory(ByVal myID As Integer) As Expression(Of Func(Of CategoryMembership, Boolean))
Dim predicate = PredicateBuilder.False(Of CategoryMembership)()
predicate = predicate.Or(Function(cm) cm.fkCategoryID = myID OrElse SomeRecursiveCall())
Return predicate
End Function
Однако я понимаю, что построитель предикатов здесь может вообще не использоваться, и может потребоваться другое направление.
Я считал, что всегда есть возможность выбрать запись Category
для запрашиваемого идентификатора и создать список идентификаторов из него и всех членов Subcategories
рекурсивно, а затем использовать этот список для оценки.Contains () сравнение в этом списке, но мне было интересно, если бы не было других вариантов, которые не выглядели бы так ужасно.