首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用多个连接循环遍历Linq结果集

问使用多个连接循环遍历Linq结果集
EN

Stack Overflow用户
提问于 2012-03-17 00:14:17
回答 1查看 3.8K关注 0票数 2

我有一个复杂的LINQ查询,如

代码语言:javascript
复制
        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将具有多个 InspectorArticles,而每个InspectorArticle将具有倍数E 210 InspectorSamples。因此,当我循环遍历结果集时,我想循环遍历每个InspectorArticle,然后循环遍历属于该InspectorArticle的每个InspectorSample,类似于:

代码语言:javascript
复制
        foreach (InspectorArticle _iart in results.First().obj2)
        {
          ...          
            foreach (InspectorSample _isamp in results.First().obj3)
            {
               ...
            }

        }

但是,由于我在我的结果集中调用了一个.First(),显然我得到了这个异常:

foreach语句不能对x类型的变量进行操作,因为x不包含“GetEnumerator”

的公共定义

那么,我如何循环遍历InspectorArticle的每个实例,然后循环该文章的InspectorSamples数呢?

谢谢。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2012-03-17 02:36:51

由于您要将记录连接在一起,此声明不正确:

现在这个结果集将只有一个ProcessBases,每个ProcessBase将有多个InspectorArticles,每个InspectorArticle将有多个InspectorSamples。

在执行查询之后,您实际拥有的是一个IEnumerable,其中IEnumerable中的每个对象都包含对ProcessBase、InspectorArticle和InspectorSample的引用。例如,在LinqPad中使用下面的代码将产生一个具有以下内容的IEnumerable:

代码:

代码语言:javascript
复制
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语句循环它,则需要使用如下代码:

代码语言:javascript
复制
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);
    }
}

使用此代码(并继续上面的示例)将获得输出:

代码语言:javascript
复制
Article ID: #3
  Sample ID: #6
  Sample ID: #7
  Sample ID: #8
Article ID: #4
  Sample ID: #9

这种方法的缺点是必须多次枚举结果列表。如果你知道这个清单总是很小的话,那就没什么大不了的了。如果列表非常大,那么您可能想出一种更好的方法来返回数据。

编辑

为了提高代码的效率,您可以按InspectorArticle.ID分组,然后按ID键创建一个Dictionary,其中包含原始的InspectorArticle和相关的InspectorSamples。

代码语言:javascript
复制
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属性中删除,因为我没有向GroupBy方法提供IEqualityComparer。如果您希望通过InspectorArticle对象本身来键入键,则需要确保两个具有相同ID的不同InspectorArticle实例被视为相等,如果您创建一个IEqualityComparer并将其传递给GroupBy方法,则可以这样做。

票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/9746082

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档