嵌套集模型树构建器






4.38/5 (6投票s)
用于从 NSM 数据构建层次树的 IEnumerable 扩展方法。
引言
这里描述的代码接收嵌套集合模型 (NSM) 数据,并从中构建对象树。
背景
关于嵌套集合模型及其相对优缺点的解释超出了本文的范围。我建议在 Google 上搜索 Joe Celko 和/或 Michael J. Kamfonas 的文章。这里有一些文章可以帮助你入门:
Using the Code
为了从一组 NSM 数据构建层次结构,每个数据点必须包含左值和右值。这些值通常是整数,但提供的扩展方法包含一个重载,允许它们是任何支持 IComparable<T>
的类型。这里是一个存储一些简单 NSM 数据的示例表
ItemData:
id description lft rgt
----------- ----------------------------------------- --------- --------
1 Root 1 12
2 RootChild1 2 3
3 RootChild2 4 11
4 RChild2_Child1 5 8
5 RChild2_Child2 9 10
7 RC2_C1_C1 6 7
这组数据表示以下树结构

* 关于编号方案的解释,请参考上述文章。
你可能像这样查询这些数据,例如
data = (from d in db.ItemDatas
select d).ToList();
一旦你拥有 IEnumerable<T>
的数据,你需要一个支持该类层次结构的类,即,一个具有负责保存与其自身类型相同“子项”的属性的类。该类还必须支持 IPopulate<T>
接口。这是必要的,以便 TreeBuilder
可以使用列表中的数据来构建目标“节点”。只需实现 IPopulate<T>.Populate(T payload)
即可使用源数据填充目标对象。对于我们的示例,我们可能有如下所示:
public class Item :
RadixSolutionsUtilities.IPopulate<ItemData>
{
public List<Item> Children
{
get;
private set;
}
public string Name { get; set; }
public Item()
{
Children = new List<Item>();
}
#region IPopulate<ItemData> Members
public void Populate(ItemData payload)
{
//here you would populate all the properties of your object
//from the source data
Name = payload.description;
}
#endregion
}
现在我们有了数据和表达该数据层次结构的类,我们只需使用以下方式构建树:
//uses the common extension method relying on ints for left
//and right
var hierarchy1 = data.AsTreeFromNSM<ItemData, Item>(
e => e.lft
, e => e.rgt
, f => f.Children);
//uses the more generic extension method allowing for any type
//of data to be used for left and right
var hierarchy2 = data.AsTreeFromNSM<ItemData, Item, int>(
e => e.lft
, e => e.rgt
, f => f.Children);
第一个 lambda 指向保存“左”数据的属性。第二个 lambda 指向保存“右”数据的属性。第三个 lambda 指向目标类型上应存储下级层次结构的位置的属性。
在第二次调用中,使用的第三个泛型是 int
,因为在我们的示例中,列 lft 和 rgt 是 int
类型。如果你有一些外星空间数据想要用来表示计数系统,请在第三个泛型参数中指定其类型。只需记住泛型约束,即它必须实现 IComparable<T>
,以便 TreeBuilder
知道如何对数据进行排序。
关注点
我确信很多人会指出更有效的方法来完成这些操作中的一些,并且请发布这些信息,但我很高兴这个方法能够工作。