我有一个复杂的 LINQ 查询,例如
var results = from obj1 in context.ProcessBases
join obj2 in context.InspectorArticles
on obj1.ID equals obj2.ProcessBaseID
join obj3 in context.InspectorSamples
on obj2.ID equals obj3.InspectorArticleID
where obj1.ID == _processBaseID
select new {obj1, obj2, obj3,};
现在这个结果集将只有一个 ProcessBases
,每个ProcessBase
将有MULTIPLE InspectorArticles
并且每个 InspectorArticle
将有 MULTIPLE InspectorSamples
。因此,当我循环遍历结果集时,我想循环遍历每个 InspectorArticle
,然后循环遍历属于该 InspectorArticle
的每个 InspectorSample
,像这样:
foreach (InspectorArticle _iart in results.First().obj2)
{
...
foreach (InspectorSample _isamp in results.First().obj3)
{
...
}
}
但是由于我在结果集上调用了 .First()
,显然我得到了这个异常:
foreach statement cannot operate on variables of type x because x does not contain a public definition for 'GetEnumerator'
那么如何循环遍历 InspectorArticle
的每个实例,然后循环遍历该文章的 InspectorSamples
数量?
谢谢。
最佳答案
由于您将记录连接在一起,因此此语句不正确:
Now this result set will have only ONE ProcessBases, each ProcessBase will have MULTIPLE InspectorArticles and each InspectorArticle will have MULTIPLE InspectorSamples.
执行查询后,您实际得到的是 IEnumerable
其中 IEnumerable
中的每个对象包含对 ProcessBase
的引用,一个InspectorArticle
和一个InspectorSample
。例如,在 LinqPad 中使用以下代码将产生 IEnumerable
包含以下内容:
代码:
void Main()
{
var processBases = new List<ProcessBase>();
var inspectorArticles = new List<InspectorArticle>();
var inspectorSamples = new List<InspectorSample>();
processBases.Add(new ProcessBase { ID = 1 });
processBases.Add(new ProcessBase { ID = 2 });
inspectorArticles.Add(new InspectorArticle { ID = 3, ProcessBaseID = 1 });
inspectorArticles.Add(new InspectorArticle { ID = 4, ProcessBaseID = 1 });
inspectorArticles.Add(new InspectorArticle { ID = 5, ProcessBaseID = 2 });
inspectorSamples.Add(new InspectorSample { ID = 6, InspectorArticleID = 3 });
inspectorSamples.Add(new InspectorSample { ID = 7, InspectorArticleID = 3 });
inspectorSamples.Add(new InspectorSample { ID = 8, InspectorArticleID = 3 });
inspectorSamples.Add(new InspectorSample { ID = 9, InspectorArticleID = 4 });
inspectorSamples.Add(new InspectorSample { ID = 10, InspectorArticleID = 5 });
inspectorSamples.Add(new InspectorSample { ID = 11, InspectorArticleID = 5 });
var processBaseID = 1;
var results = from obj1 in processBases
join obj2 in inspectorArticles on obj1.ID equals obj2.ProcessBaseID
join obj3 in inspectorSamples on obj2.ID equals obj3.InspectorArticleID
where obj1.ID == processBaseID
select new { obj1, obj2, obj3 };
Console.WriteLine(results);
}
public class ProcessBase
{
public int ID { get; set; }
}
public class InspectorArticle
{
public int ID { get; set; }
public int ProcessBaseID { get; set; }
}
public class InspectorSample
{
public int ID { get; set; }
public int InspectorArticleID { get; set; }
}
结果:
因此,如果您想按原样保留 Linq 语句并使用多个 foreach 语句循环遍历它,则需要使用类似以下代码的内容:
foreach(var article in results.GroupBy(g => g.obj2.ID))
{
Console.WriteLine("Article ID: #{0}", article.Key);
foreach(var sample in results
.Where(s => s.obj3.InspectorArticleID == article.Key)
.Select(s => s.obj3))
{
Console.WriteLine("\tSample ID: #{0}", sample.ID);
}
}
使用此代码(并继续上面的示例)应该会得到输出:
Article ID: #3
Sample ID: #6
Sample ID: #7
Sample ID: #8
Article ID: #4
Sample ID: #9
这种方法的缺点是您必须多次枚举结果列表。如果您知道这个列表总是很小,那么这没什么大不了的。如果列表非常大,那么您可能需要想出更好的方法来返回数据。
编辑
为了使代码更高效,您可以按 InspectorArticle.ID
进行分组然后创建一个Dictionary
由ID
键入,并包含原始 InspectorArticle
以及相关的InspectorSamples
.
var articles = results.GroupBy(g => g.obj2.ID)
.ToDictionary(k => k.Key, v => new {
InspectorArticle = v.Select(s => s.obj2).First(),
InspectorSamples = v.Select(s => s.obj3) });
foreach(var article in articles.OrderBy(a => a.Key).Select(kv => kv.Value))
{
Console.WriteLine("Article ID: #{0}", article.InspectorArticle.ID);
foreach(var sample in article.InspectorSamples)
{
Console.WriteLine("\tSample ID: #{0}", sample.ID);
}
}
上面的代码将产生与我的第一个示例相同的结果,但对于较长的文章和示例列表会更有效,因为它在构建 Dictionary
时只会枚举整个列表一次。 .
请注意,我键入了 Dictionary
关闭ID
属性,因为我没有提供 IEqualityComparer
到GroupBy
方法。如果您更愿意输入 InspectorArticle
对象本身,您需要确保两个不同的 InspectorArticle
具有相同 ID
的实例被视为相等,如果您创建 IEqualityComparer
就可以做到这一点并将其传递到 GroupBy
方法。
关于c# - 使用多个联接循环遍历 Linq 结果集,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9746082/