反向递归LINQ到自引用数据表

时间:2014-02-24 14:33:15

标签: c# linq

| ID | PrID | Name |
|------------------|
|  1 | null | N1   |
|  2 |    1 | N2   |
|  3 |    2 | N3   |
|  4 |    3 | N4   |

您好,我有以下自引用数据表。我的输入参数是N1,我需要找到它的最后一个孩子N4。请帮忙写LINQ查询。 谢谢!

3 个答案:

答案 0 :(得分:0)

这个问题非常相似。基本上你需要编写一个扩展方法,因为LINQ不是为处理这样​​的场景而设计的。

Walking a hierarchy table with Linq

答案 1 :(得分:0)

不是最好的LINQ候选者,但是,这个递归扩展应该有效:

public static IEnumerable<T> Traverse<T>(this IEnumerable<T> source, Func<T, IEnumerable<T>> fnRecurse)
{
    foreach (T item in source)
    {
        yield return item;

        IEnumerable<T> seqRecurse = fnRecurse(item);
        if (seqRecurse != null)
        {
            foreach (T itemRecurse in Traverse(seqRecurse, fnRecurse))
            {
                yield return itemRecurse;
            }
        }
    }
}

以下是您的示例数据:

DataTable tbldata = new DataTable();
tbldata.Columns.Add("ID", typeof(int));
tbldata.Columns.Add("PrID", typeof(int));
tbldata.Columns.Add("Name", typeof(string));
tbldata.Rows.Add(1, null, "N1");
tbldata.Rows.Add(2, 1, "N2");
tbldata.Rows.Add(3, 2, "N3");
tbldata.Rows.Add(4, 3, "N4");

此查询返回您想要的结果:

string parentName = "N1";
IEnumerable<DataRow> rows = tbldata.AsEnumerable();
DataRow parentRow = rows.FirstOrDefault(r => r.Field<string>("Name") == parentName);
DataRow lastChild = null;
if(parentRow != null)
{
    int parentID = parentRow.Field<int>("ID");
    lastChild = rows.Where(r => r.Field<int?>("PrID") == parentID)
        .Traverse(parent => rows
            .Where(child => child.Field<int?>("PrID") == parent.Field<int>("ID")))
        .LastOrDefault();
}

输出:

Console.Write(String.Join(",", lastChild.ItemArray)); // 4,3,N4

答案 2 :(得分:-1)

这在LINQ中可能是可撤消的。

您可以创建一个存储过程,使用WHILE循环来查找最后一个子节点,也可以将整个表拉到应用程序并使用循环解析它

Item i = FetchFirst();
while (i.GetNext() != null)
    i = i.GetNext();

然后i将存储结果。 GetNext()加载下一项,FetchFirst()加载N1项。