我们是否需要 LINQ 中的外部连接的连接子句?
Do we need the join clause for outer joins in LINQ?
This MSDN page给出了以下外连接的例子:
class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
class Pet
{
public string Name { get; set; }
public Person Owner { get; set; }
}
public static void LeftOuterJoinExample()
{
Person magnus = new Person { FirstName = "Magnus", LastName = "Hedlund" };
Person terry = new Person { FirstName = "Terry", LastName = "Adams" };
Person charlotte = new Person { FirstName = "Charlotte", LastName = "Weiss" };
Person arlene = new Person { FirstName = "Arlene", LastName = "Huff" };
Pet barley = new Pet { Name = "Barley", Owner = terry };
Pet boots = new Pet { Name = "Boots", Owner = terry };
Pet whiskers = new Pet { Name = "Whiskers", Owner = charlotte };
Pet bluemoon = new Pet { Name = "Blue Moon", Owner = terry };
Pet daisy = new Pet { Name = "Daisy", Owner = magnus };
// Create two lists.
List<Person> people = new List<Person> { magnus, terry, charlotte, arlene };
List<Pet> pets = new List<Pet> { barley, boots, whiskers, bluemoon, daisy };
var query = from person in people
join pet in pets on person equals pet.Owner into gj
from subpet in gj.DefaultIfEmpty()
select new { person.FirstName, PetName = (subpet == null ? String.Empty : subpet.Name) };
foreach (var v in query)
{
Console.WriteLine("{0,-15}{1}", v.FirstName + ":", v.PetName);
}
}
// This code produces the following output:
//
// Magnus: Daisy
// Terry: Barley
// Terry: Boots
// Terry: Blue Moon
// Charlotte: Whiskers
// Arlene:
join
关键字有什么意义?以下查询具有相同的结果。
var query2 = from person in people
from pet in pets.Where (p => p.Owner.Equals(person)).DefaultIfEmpty()
select new { person.FirstName, PetName = (pet == null ? String.Empty : pet.Name) };
这两个在功能上是等价的吗?如果不是,它们有何不同?如果是,使用 join
关键字进行外连接有什么好处?似乎是编写 'where' 子句的一种奇特方式。但也许在其他情况下它真的很有用?
注意:我意识到 join 子句很可能也用于内部联接、组联接等,我想了解是否有理由将它用于外部联接。
您 也没有 将其用于内部联接,但在许多情况下,在 "where" 子句中执行此逻辑效率较低。当为具有外键索引而不是简单的对象集合的 table 完成时,这会变得更加明显。
我知道你的问题是关于 LINQ 的,但由于其中许多概念来自 SQL,因此值得一提:历史上,SQL 的某些方言根本没有连接子句 -您将用逗号列出 tables,并在 where 子句中执行所有逻辑,在 Oracle 的 tables 上使用各种特定于供应商的语法 [(+)
,*=
和 =*
用于 left/right 在 MS SQL 上加入,等等] 以指示外部加入。
在 Linq-to-Objects 中,它们将编译为不同的查询,并且可能具有显着不同的性能。
join
运算符将在内部为 "right-hand" 集创建一个 Lookup
,这将使检索匹配结果更快,因为它按哈希码组织项目。
使用 Where
子句将按以下方式执行查找(粗略的伪代码,而不是确切的实现):
foreach(var left in leftSet)
{
foreach(var right in rightSet)
{
if(left.key equals right.key)
yields return result
}
}
对于左侧集合中的每个对象,您正在对右侧集合进行全面扫描以查找 "matching" 个对象。对于大型集合,性能影响可能非常显着。
请注意,Where
方法可以做到 "joins" 而 join
做不到,因为 join
只支持等值连接。
对于 Ling-to-SQL、Linq-to-EF 等,差异在很大程度上取决于底层查询提供程序。使用 cross-join/where 可能会获得与使用左连接类似的性能,但您必须尝试并进行测量才能确定。
This MSDN page给出了以下外连接的例子:
class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
class Pet
{
public string Name { get; set; }
public Person Owner { get; set; }
}
public static void LeftOuterJoinExample()
{
Person magnus = new Person { FirstName = "Magnus", LastName = "Hedlund" };
Person terry = new Person { FirstName = "Terry", LastName = "Adams" };
Person charlotte = new Person { FirstName = "Charlotte", LastName = "Weiss" };
Person arlene = new Person { FirstName = "Arlene", LastName = "Huff" };
Pet barley = new Pet { Name = "Barley", Owner = terry };
Pet boots = new Pet { Name = "Boots", Owner = terry };
Pet whiskers = new Pet { Name = "Whiskers", Owner = charlotte };
Pet bluemoon = new Pet { Name = "Blue Moon", Owner = terry };
Pet daisy = new Pet { Name = "Daisy", Owner = magnus };
// Create two lists.
List<Person> people = new List<Person> { magnus, terry, charlotte, arlene };
List<Pet> pets = new List<Pet> { barley, boots, whiskers, bluemoon, daisy };
var query = from person in people
join pet in pets on person equals pet.Owner into gj
from subpet in gj.DefaultIfEmpty()
select new { person.FirstName, PetName = (subpet == null ? String.Empty : subpet.Name) };
foreach (var v in query)
{
Console.WriteLine("{0,-15}{1}", v.FirstName + ":", v.PetName);
}
}
// This code produces the following output:
//
// Magnus: Daisy
// Terry: Barley
// Terry: Boots
// Terry: Blue Moon
// Charlotte: Whiskers
// Arlene:
join
关键字有什么意义?以下查询具有相同的结果。
var query2 = from person in people
from pet in pets.Where (p => p.Owner.Equals(person)).DefaultIfEmpty()
select new { person.FirstName, PetName = (pet == null ? String.Empty : pet.Name) };
这两个在功能上是等价的吗?如果不是,它们有何不同?如果是,使用 join
关键字进行外连接有什么好处?似乎是编写 'where' 子句的一种奇特方式。但也许在其他情况下它真的很有用?
注意:我意识到 join 子句很可能也用于内部联接、组联接等,我想了解是否有理由将它用于外部联接。
您 也没有 将其用于内部联接,但在许多情况下,在 "where" 子句中执行此逻辑效率较低。当为具有外键索引而不是简单的对象集合的 table 完成时,这会变得更加明显。
我知道你的问题是关于 LINQ 的,但由于其中许多概念来自 SQL,因此值得一提:历史上,SQL 的某些方言根本没有连接子句 -您将用逗号列出 tables,并在 where 子句中执行所有逻辑,在 Oracle 的 tables 上使用各种特定于供应商的语法 [(+)
,*=
和 =*
用于 left/right 在 MS SQL 上加入,等等] 以指示外部加入。
在 Linq-to-Objects 中,它们将编译为不同的查询,并且可能具有显着不同的性能。
join
运算符将在内部为 "right-hand" 集创建一个 Lookup
,这将使检索匹配结果更快,因为它按哈希码组织项目。
使用 Where
子句将按以下方式执行查找(粗略的伪代码,而不是确切的实现):
foreach(var left in leftSet)
{
foreach(var right in rightSet)
{
if(left.key equals right.key)
yields return result
}
}
对于左侧集合中的每个对象,您正在对右侧集合进行全面扫描以查找 "matching" 个对象。对于大型集合,性能影响可能非常显着。
请注意,Where
方法可以做到 "joins" 而 join
做不到,因为 join
只支持等值连接。
对于 Ling-to-SQL、Linq-to-EF 等,差异在很大程度上取决于底层查询提供程序。使用 cross-join/where 可能会获得与使用左连接类似的性能,但您必须尝试并进行测量才能确定。