2012-03-17 82 views
1

我有一个像通过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,}; 

一个复杂的LINQ查询现在这个结果集将只有ONEProcessBases,每个ProcessBase将有InspectorArticles每个InspectorArticle会有多个InspectorSamples。所以,当我在结果集中循环,我想遍历每个InspectorArticle,然后遍历属于该InspectorArticle每个InspectorSample,是这样的:

 foreach (InspectorArticle _iart in results.First().obj2) 
     { 
      ...   
      foreach (InspectorSample _isamp in results.First().obj3) 
      { 
       ... 
      } 

     } 

但是,因为我已经叫我的结果.First()设置显然我得到这个异常:

foreach语句不能在X型的变量操作,因为X不 不包含“的GetEnumerator”

一个公共定义

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

谢谢。

回答

4

既然你要加入的记录在一起,这种说法是不正确的:

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

你将真正拥有你执行查询后是IEnumerable凡在IEnumerable每个对象都包含一个ProcessBase,一个InspectorArticleInspectorSample参考。例如,在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; } 
} 

结果:

linqpad results

所以,如果你想要保持Linq语句的原样,并用多个foreach语句遍历它,你需要使用类似代码belo女:

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,然后创建由ID键控Dictionary,并包含原始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财产的,因为我没有提供一个IEqualityComparerGroupBy方法。如果您宁愿使用InspectorArticle对象本身,则需要确保将具有相同ID的两个不同InspectorArticle实例视为相同,如果您创建IEqualityComparer并将其传递给GroupBy方法,则可以完成此操作。

+0

非常感谢你:) – 2012-03-17 07:25:32

+0

很高兴我能帮忙! – rsbarro 2012-03-17 11:37:44

+1

@ClunkyCoder再想一想,如果你有更长的列表,发布一个更有效的方法。 – rsbarro 2012-03-17 15:56:35