外连接 LINQ

4

我刚接触Linq to Object,对于在两个上下文中使用from子句有一个问题:

1)像下面的查询一样执行交叉连接:

  var q1 = from person in people
      from job in jobs
      select new {person, job}

2) 执行外连接

  var q2 = from person in people
     join pet in pets on person equals pet.Owner into gj
     from subpet in gj
     select new { OwnerName = person.FirstName, PetName = subpet.Name };

第二个from子句是作为交叉连接还是根据上下文进行评估?因为q1将产生people.Count * jobs.Count个元素,但q2只会产生people.Count个元素。
3个回答

3
根据微软文档,要使第二个查询成为左外连接,您应该使用DefaultIfEmpty方法,如此处所示。from子句始终以相同的方式计算:它返回序列中的每个元素,无论是预定义源还是上下文变量。
编辑:我将从头开始解释。首先,您需要将人和宠物进行内部连接(具体来说是组连接)。然后,您从生成的集合(实际上是人-宠物集合)选择新的匿名对象,获取人名(从gj集合元素中)和子宠物名称(对于gj集合元素中的每个宠物)。我认为第二个from不会进行交叉连接,因为它从gj中选择,并且每个人已经是gj集合元素的一部分。如果在第二个from子句中调用gj.DefaultIfEmpty()方法,则没有任何宠物的人(gj集合元素内的空宠物集合)将添加到结果集中。您可以阅读以下文章以更好地理解它:

对于查询“q1”,第二个“from”作为人员和工作元素之间的交叉连接,那么第二个查询的情况是什么? - anouar.bagari
在我看来,from子句并不像交叉连接那样起作用,但是select确实是。from只是执行交叉连接的手段,因为它提供了序列中的元素。在第二个示例中,您将person-pet内部连接到gj,并使用第二个from从结果集中选择每个元素,仅此而已。要执行左外连接,您应该将右值(来自gj集)替换为null,以表示没有宠物的人。 - Dmitry Polyanitsa
这是否意味着第一个from作为foreach循环,而第二个from作为嵌套在第一个循环内部的foreach循环? - anouar.bagari
我已经更新了我的帖子,并尝试更详细地解释这个问题。 - Dmitry Polyanitsa
我无法解释为什么会出现这种情况,但我认为编译器“知道”person在gj中,并且不会将该部分翻译成crossjoin。我不确定这一点,但你可以尝试使用任何可用的.NET反编译器对代码进行反编译并检查它。当你查看已翻译的代码时,我认为你会找到答案。 - Dmitry Polyanitsa

0

join 通常用于基于匹配键关联两个序列的元素,因此它通常是内连接,但这取决于您如何定义匹配,例如以下内容将产生交叉连接:

List<int> A = new List<int> { 1, 2, 3, 4, 5 };
List<int> B = new List<int> { 1, 2, 3, 4, 5 };
var c = (from a in A join b in B on 1 equals 1 select new { a, b }).ToList();

我的问题是关于“from”子句(查询中的第二个)而不是“join”,它对于两个查询(q1和q2)是否以相同的方式起作用,或者它会为第一个查询产生交叉连接,为第二个查询产生外连接? - anouar.bagari

0

From子句的评估基于上下文。如果没有上下文,您将无法使用上下文变量,例如gj。但是,如果您不使用该上下文,就像在第一个查询中一样,它的行为与交叉连接相同。

您说第二个查询给出了意外数量的元素。也许您不应该关注这一点,而应该关注您获得的元素以及它们与您期望的有何不同。


对于查询“q1”,第二个“from”作为人员和工作元素之间的交叉连接,那么第二个查询的情况是什么? - anouar.bagari

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接