Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/linq/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# LINQ:计算嵌套元素的总数_C#_Linq - Fatal编程技术网

C# LINQ:计算嵌套元素的总数

C# LINQ:计算嵌套元素的总数,c#,linq,C#,Linq,我有一个包含一对多自引用关系的数据表: Plant { ID, Name, ParentID } 我正在尝试创建一个linq查询,它将告诉我来自一种植物的后代总数 例如: 我有5种植物: One {ID = 1, Name = Pine, Parent = null};// This is the root Two {ID = 2, Name = Evergreen, Parent = 1} Three {ID = 3, Name = Winter Eve

我有一个包含一对多自引用关系的数据表:

Plant
{ 
  ID,
  Name,
  ParentID
}
我正在尝试创建一个linq查询,它将告诉我来自一种植物的后代总数

例如:

我有5种植物:

One {ID = 1, Name = Pine, Parent = null};// This is the root
    Two {ID = 2, Name = Evergreen, Parent = 1}
        Three {ID = 3, Name = Winter Evergreen, Parent = 2}
    Four {ID = 4, Name = Christmas Tree, Parent = 1}
Five {ID = 5, Name = Maple, Parent = null};// This is the root
当我使用
ID=1
的输入调用我的LINQ查询时,我希望它
返回3
,因为
One
有3个后代;二,三,四<代码>五个不是一个的死者

我考虑这样做的唯一方法是对内部结果进行嵌套的递归linq查询。我不知道如何做到这一点,我觉得似乎有一个更简单的方法


如果有必要的话,我正在使用C#4.0和LINQ。

EDIT通过@Kirk Woll comment添加支持LINQ到SQL的代码

class Program
{
    private static Table<Plant> plants;

    static void Main(string[] args)
    {
        using (var dataContext = new DataClasses1DataContext())
        {
            plants = dataContext.Plants;
            var treesNodes = GetTreesNodes(plants.Where(plant => plant.ID == 1));
            Console.WriteLine(string.Join(",",
                                          treesNodes.Select(plant => plant.ID)));
        }
    }

    public static IEnumerable<Plant> GetTreesNodes(IEnumerable<Plant> roots)
    {
        if(!roots.Any())
        {
            return roots;
        }

        var children = roots.SelectMany(root => 
                                    plants.Where(plant => plant.Parent == root));
        return roots.Union(GetTreesNodes(children));
    }

}

代码假定没有循环引用。

如果您使用的是SQL Server,则需要构造的查询将是:

DECLARE @TargetElementId int
SET @TargetElementId = 1;

WITH Plants AS
(
    SELECT ID, Name, ParentId
    FROM PlantsTable
    WHERE ParentId = @TargetElementId

    UNION ALL

    SELECT ID, Name, ParentId
    FROM PlantsTable
    INNER JOIN Plants ON PlantsTable.ParentId = Plants.ID
)
SELECT COUNT(ID) - 1 FROM Plants

我不相信使用LinqToSql可以做到这一点,请看,这是一个性质类似的问题。

您提到了一个表,所以我假设您的目标是可以转换为SQL的东西?i、 e.LinqToSql?(针对LinqToObject,有简单的解决方案可用)她提到了“数据表”和“一对多关系”,因此我认为她需要一些可以转换为SQL的东西。但这并不能做到这一点。换句话说,她需要一些能与IQueryable一起工作的东西。@Kirk Woll,你说得有道理。如果它是一个加载的数据表,那么LinqToObject可能会解决它(即使可能有更有效的解决方案)。如果它是一个需要转换为SQL的“活动”表,那么代码可能无法工作。@Kirk Woll,仔细想想,我找不到转换为SQL有困难的部分。你能指出有问题的代码吗?很有可能你是对的,但我自己找不到问题:)@Kirk Woll,你是对的,原始代码无法转换为SQL。将代码更新为可转换为SQL的版本。谢谢!我正试图让您的编辑正常工作,但我在var子项分配中的
工厂
部分遇到了问题。是否应该是
?我看到它引用了静态表,但是我在声明表时遇到了一个错误。这比linq解决方案更好更快。我会用这个。我只需要刷掉.Net中的SQLConnection内容。我来了!这就是我最终实现的。它起作用了。我想我可能必须修改它,以便从另一个查询中实际读取参数,但这是另一天的事情。
[Test]
public void ExampleTest()
{
    var One = new Plant() {ID = 1, Name = "Pine", Parent = 0}; 
    var Two = new Plant() {ID = 2, Name = "Evergreen", Parent = 1};
    var Three = new Plant() {ID = 3, Name = "Winter Evergreen", Parent = 2};
    var Four = new Plant() {ID = 4, Name = "Christmas Tree", Parent = 1};
    var Five = new Plant() {ID = 5, Name = "Maple", Parent = 0};

    plants = new []{One,Two,Three,Four,Five};

    var nestedElements = GetTreesNodes(new[]{One});
    var numOfNestedElementsWithoutRoot = nestedElements.Count()-1;

    Assert.That(numOfNestedElementsWithoutRoot, Is.EqualTo(3));
}
DECLARE @TargetElementId int
SET @TargetElementId = 1;

WITH Plants AS
(
    SELECT ID, Name, ParentId
    FROM PlantsTable
    WHERE ParentId = @TargetElementId

    UNION ALL

    SELECT ID, Name, ParentId
    FROM PlantsTable
    INNER JOIN Plants ON PlantsTable.ParentId = Plants.ID
)
SELECT COUNT(ID) - 1 FROM Plants