65.9K
CodeProject 正在变化。 阅读更多。
Home

嵌套集模型树构建器

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.38/5 (6投票s)

2009年4月9日

CPOL

2分钟阅读

viewsIcon

42812

downloadIcon

779

用于从 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,因为在我们的示例中,列 lftrgtint 类型。如果你有一些外星空间数据想要用来表示计数系统,请在第三个泛型参数中指定其类型。只需记住泛型约束,即它必须实现 IComparable<T>,以便 TreeBuilder 知道如何对数据进行排序。

关注点

我确信很多人会指出更有效的方法来完成这些操作中的一些,并且请发布这些信息,但我很高兴这个方法能够工作。

© . All rights reserved.