我有一个名为Device
的对象。 Device
可以包含一个父级 Device
。 Device
也可以包含 n 子Devices
。
我有一个下拉列表,显示所有可选的Devices
。我可以非常轻松地获取数据库中的所有Devices
- db.Devices
。
层次结构可以是无限级别。
我需要所有Devices
不高于或低于树中给定Device
的所有Devices
。基本上我要求Device
与给定的Device
无关(父母/祖父母/祖父母/祖父母/等或儿童/孙子/曾孙子等)。我还需要从列表中排除给定的{{1}}。
最好的方法是什么?我应该使用递归吗?
(我正在使用带有SQL Server数据库的C#和Entity Framework,因此我可以使用Linq To SQL或使用模型本身。)
答案 0 :(得分:3)
我的方法是首先获得设备D
的所有兄弟姐妹:
P = parent of the device
sibs = {all children of P that are not D}
任何d in sibs
的后代都与D
无关。继续走上家谱:
G = grandparent of the device
sibs = sibs union {all children of G that are not P}
继续这样,集合sibs
及其所有后代就是你所追求的集合。
在伪代码中:
D = device;
siblings = {};
while (D has parent) {
P = parent(D);
siblings = siblings union (children(P) \ D);
D = P;
}
return descendants(siblings);
答案 1 :(得分:1)
同意Denis - 这取决于您的数据存储方式。
我建议您使用TSQL HierarchyId datatype实现层次结构。然后,您可以使用IsDescendent
非常轻松地检查行是否是另一行的后代DECLARE @searchId HierarchyId -- select your id
SELECT @searchId = HierarchyId FROM Devices WHERE DeviceId = 1
SELECT * FROM Devices
WHERE
-- not children
DeviceHierarchyId.IsDescendantOf(@seachId) = 0
-- not parents
AND @searchId.IsDescendantOf(DeviceHierarchyId) = 0
修改强>
要简要说明HierarchyId数据类型及其工作原理,请考虑每个项目在根节点下的层次结构中都有一个位置。 (如果您有多个自然根,则将每个根放在超级根下)。每个hierarchyid列存储item的完整层次结构位置。例如
Id | ParentId | HierarchyId
1 | null | \1
2 | 1 | \1\2
3 | 1 | \1\3
4 | 3 | \1\3\4
等等。要检查项目是否是另一个项目的子项,只需检查hierarchyId是否包含在另一行的hierarchyId中 - 例如4是3的子项,因为整个\1\3
包含在其hierarchyId \1\3\4
中,但4不是2的子项,因为\1\2
未包含在hierarchyId中。
要查看itemA是否为itemB的父,请检查itemB是否为itemA的子项。
最后,您实际上不需要进行任何比较。 TSQL HierarchyId类型包含许多方法,其中一种方法是我在上面突出显示的IsDescendantOf
方法。因此像hierarcyId1.IsDescendantOf(hierarchyId2)
这样的用法会执行我在此处描述的那种检查。 hierarchyIds是二进制的,可以在数据库中快速比较。
在处理数据库层次结构时,我会尽可能使用hierarchyId。
答案 2 :(得分:0)
如果父母有索引,可以尝试
select *
from devices as child
where exists(select null
from devices as parent
where parent.id = child.parent)
我的SQL并不完美,但这是我将使用的基本方法。
答案 3 :(得分:0)
这取决于您将树存储在数据库中的方式。有nested sets model允许直接在数据库中进行此类查询。
答案 4 :(得分:0)
我的下意识算法解决方案是一种“标记 - 扫描”类型的解决方案(来自垃圾收集器理论)。
http://en.wikipedia.org/wiki/Garbage_collection_(computer_science)#Na.C3.AFve_mark-and-sweep
基本上你遍历整个设备层次结构并标记那些“可追踪”的设备,这意味着它们可以通过另一个设备“使用递归”到达。
任何未标记的内容,您都会“扫描”GC。在您的情况下,任何未标记的是您正在寻找的集合。