由于您将记录连接在一起,因此此陈述不正确:
现在这个结果集将只有一个 ProcessBase,每个 ProcessBase
将有 MULTIPLE InspectorArticles 并且每个 InspectorArticle 将
有多个 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 分组,然后创建一个以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 属性分开,因为我没有为GroupBy 方法提供IEqualityComparer。如果您希望通过 InspectorArticle 对象本身作为键,则需要确保具有相同 ID 的两个不同 InspectorArticle 实例被视为相等,如果您创建一个 IEqualityComparer 并通过将其放入GroupBy 方法中。