我具有用于在VB.Net中填充TreeList的分层数据表,如下所示:
ID ParentID Name
----------------------
1 NUll a
2 NUll b
3 2 c
4 1 d
5 3 e
6 5 f
7 6 g
8 5 h
我的问题: 如何在vb.net中使用Linq获取节点(ID)的所有子节点列表? 请帮助我。
答案 0 :(得分:0)
不幸的是,我对VB的了解不足,无法给您VB的答案。我将用C#给出答案。您可能会理解这个主意。也许您可以添加VB翻译?
您忘记描述您的Node类。我认为您不仅要孩子,而且要孙子(等等)。
class TreeNode
{
public int Id {get; set;}
public string Name {get; set;}
// every node has zero or more sub-nodes:
public IEnumerable<TreeNode> Nodes {get; set;}
}
您希望层次结构深入到未知的层次。因此,您不能使用标准LINQ函数。但是您可以轻松扩展LINQ来创建自己的LINQ。参见E xtension Function demystified
public static IEnumerable<TreeNode> AsTreeNodes(this IEnumerable<Person> persons)
{
// Top TreeNodes: all persons without a Parent:
return persons.AsTreeNodes((int?)null);
}
使用递归返回所有具有parentId的人的节点序列的实际函数:
public static IEnumerable<TreeNode> AsTreeNodes(this IEnumerable<Person> persons, int? parentId)
{
// Top Nodes: all persons with parentId
var personsWithParentId = persons.Where(person.ParentId == parentId);
foreach (var person in personsWithParentId)
{
// every person will become one TreeNode with sub-nodes using recursion
TreeNode node = new TreeNode()
{
Id = person.Id,
Name = person.Name,
// get all my Children and Children's children:
Nodes = persons.ToNodeCollection(person.Id),
};
yield return node;
}
}
请注意,我选择返回IEnumerable而不是List / Array。这样,只有在您真正枚举项目时才可以创建它们。因此,如果您不想使用ID为1的人的节点,则将不会创建其所有孩子。
用法:获取“乔治·华盛顿”所有后代的家庭等级:
IEnumerable<Person> allPersons = ...
IEnumerable<TreeNode> allFamilyHierarchies = allPersons.AsTreeNodes();
IEnumerable<TreeNode> washingtonFamily = allFamilyHierarchies
.Where(familyHierarchy => familyHierarchy.Name == "George Washington");
注意:到目前为止,尚未创建TreeNode,仅创建了IEnumerable。
一旦执行不返回IEnumerable的操作,枚举就会开始,
例如foreach
,ToList
,Any
,FirstOrDefault
。
因此,所有非华盛顿族都将被忽略,不会创建顶级节点或子节点。
如果仔细观察,您会发现要查找整个集合中我必须枚举的所有子级,找到具有特定ParentId的所有Persons。如果先将所有人分组为具有相同ParentId的组,然后将这些组放入以ParentId为键的Dictionary中,则可以更有效地完成此操作。这样,查找具有ID X的父代的所有子代将非常快:
var personsWithSameParentId = persons.GroupBy(person => person.ParentId);
var dictionary = personsWithSameParentId.ToDictionary(group => group.Key)
字典中的每个元素都具有等于parentId的键,并且所有具有此parentId的人都将其作为元素。
TreeNode CreateNodeForPerson(Person person)
{
IEnumerable<Person> children = dictionary[person.Id];
IEnumerable<TreeNode> childNodes = children
.Select(child => CreateNodeforPerson(child));
return new TreeNode()
{
Id = person.Id,
Name = person.Name,
Nodes = childNodes,
};
}
您将看到相同的递归。但是一旦有了字典,就不必枚举完整的Person集合,只需访问要为其创建点头的Person的子代/子代子代。