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