班级结构
public clas Item
{
public Item Parent { get; set; }
public string Code { get; set; }
}
示例树
AAA
- AAB
- BBB
CCC
- CCA
所以我想通过CODE == BBB过滤树,结果应该是
AAA
- AAB
- BBB
但如果我像这样过滤
IQueryable<Item> itemsQuery = GetQuery();
itemsQuery = itemsQuery.Where(x => x.Code == "BBB")
结果不包含父节点。那么,如果子节点满足某些条件,如何包含父节点?
答案 0 :(得分:0)
简单来说,使用EF无法获得递归树。 EF返回平面集合。但是,有一些解决方法。
变式1:
添加到您的商品public Item Root { get; set; }
和public ICollection<Item> AllSiblings { get; set; }
属性,它将所有商品指向实际的根,第二个是另一种方式(所有嵌套商品)。
查询比看起来像:
IQueryable<Item> itemsQuery = GetQuery().Include(x => x.AllSiblings);
itemsQuery = itemsQuery.Where(x => x.Code == "BBB" || x.AllSiblings.Any(s => s.Code == "BBB")).ToList();
现在你的应用程序中有所有项目,你可以递归地在C#中创建树。
变体2:
您可以进行多次SQL查询以获取找到的项目的每个父项。不建议这样做,因为在更多找到的结果上它会变慢。
答案 1 :(得分:0)
这里很难应用LinQ,因为没有从父项到子项的引用。在应用过滤器后对父进行简单枚举怎么办?它将为您提供树中所有匹配项的列表,然后您可能需要以“树”方式打印它。这是一个BFS示例
IQueryable<Item> itemsQuery = items.AsQueryable();
itemsQuery = itemsQuery.Where(x => x.Code == "BBB");
var bfsQueue = new Queue<Item>(itemsQuery);
var matchedItemsSet = new HashSet<Item>();
while (bfsQueue.Count > 0) {
var item = bfsQueue.Dequeue();
matchedItemsSet.Add(item);
var parent = item.Parent;
if (parent != null && !matchedItemsSet.Contains(parent))
{
bfsQueue.Enqueue(parent);
}
}
foreach (var item in matchedItemsSet) {
Console.WriteLine(item.Code);
}
答案 2 :(得分:0)
我更喜欢通用方法。
public static IEnumerable<T> SelectUntil<T>(this T element, Func<T, T> nextMemberSelector, Func<T, bool> stopCondition)
{
while (!stopCondition(element))
{
yield return element;
element = nextMemberSelector(element);
}
}
public static IEnumerable<Item> GetAncestors(this Item e)
{
// Or don't Skip(1) if you need the child itself included.
return e.SelectUntil(T => T.Parent, T => T.Parent == null).Skip(1);
}
private static void Main(string[] args)
{
IEnumerable<Item> itemsQuery = GetQuery();
IEnumerable<Item> filter = itemsQuery.Where(T => T.Code == "BBB");
foreach (Item item in filter)
{
Item[] allParents = item.GetAncestors().ToArray();
}
}