LINQ 内连接与左连接
Posted
技术标签:
【中文标题】LINQ 内连接与左连接【英文标题】:LINQ Inner-Join vs Left-Join 【发布时间】:2010-10-06 05:28:17 【问题描述】:使用扩展语法,我尝试使用 LINQ 在我拥有的两个列表上创建左连接。以下来自 Microsoft 帮助,但我已对其进行了修改以显示宠物列表没有任何元素。我最终得到的是一个包含 0 个元素的列表。我认为这是因为内部连接正在发生。我想要结束的是一个包含 3 个元素(3 个 Person 对象)的列表,其中为缺失的元素填充了空数据。即左连接。这可能吗?
Person magnus = new Person Name = "Hedlund, Magnus" ;
Person terry = new Person Name = "Adams, Terry" ;
Person charlotte = new Person Name = "Weiss, Charlotte" ;
//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 daisy = new Pet Name = "Daisy", Owner = magnus ;
List<Person> people = new List<Person> magnus, terry, charlotte ;
//List<Pet> pets = new List<Pet> barley, boots, whiskers, daisy ;
List<Pet> pets = new List<Pet>();
// Create a list of Person-Pet pairs where
// each element is an anonymous type that contains a
// Pet's name and the name of the Person that owns the Pet.
var query =
people.Join(pets,
person => person,
pet => pet.Owner,
(person, pet) =>
new OwnerName = person.Name, Pet = pet.Name ).ToList();
【问题讨论】:
【参考方案1】:我认为如果你想使用扩展方法你需要使用GroupJoin
var query =
people.GroupJoin(pets,
person => person,
pet => pet.Owner,
(person, petCollection) =>
new OwnerName = person.Name,
Pet = PetCollection.Select( p => p.Name )
.DefaultIfEmpty()
).ToList();
您可能不得不使用选择表达式。在一对多关系的情况下,我不确定它是否会满足您的需求。
我认为使用 LINQ 查询语法会更容易一些
var query = (from person in context.People
join pet in context.Pets on person equals pet.Owner
into tempPets
from pets in tempPets.DefaultIfEmpty()
select new OwnerName = person.Name, Pet = pets.Name )
.ToList();
【讨论】:
哇 :) 正是我想要的! 我不知道您可以通过在查询方法周围加上括号来获得 .ToList(),谢谢! 请不要将 LINQ 声明性查询语法称为“LINQ 语法”。它们都是“LINQ 语法”。正确的命名是“查询语法”与“方法语法”。 msdn.microsoft.com/en-us/library/bb397947.aspx 后者的不当命名是“yoda-style syntax”。【参考方案2】:您需要将连接的对象放入一个集合中,然后按照 JPunyon 所说的应用 DefaultIfEmpty:
Person magnus = new Person Name = "Hedlund, Magnus" ;
Person terry = new Person Name = "Adams, Terry" ;
Person charlotte = new Person Name = "Weiss, Charlotte" ;
Pet barley = new Pet Name = "Barley", Owner = terry ;
List<Person> people = new List<Person> magnus, terry, charlotte ;
List<Pet> pets = new List<Pet>barley;
var results =
from person in people
join pet in pets on person.Name equals pet.Owner.Name into ownedPets
from ownedPet in ownedPets.DefaultIfEmpty(new Pet())
orderby person.Name
select new OwnerName = person.Name, ownedPet.Name ;
foreach (var item in results)
Console.WriteLine(
String.Format("0,-25 has 1", item.OwnerName, item.Name ) );
输出:
Adams, Terry has Barley
Hedlund, Magnus has
Weiss, Charlotte has
【讨论】:
感谢 Gishu - 非常有用的信息。 我认为您可以将两行:join pet...
和 from ownedPet...
替换为单行:from pet in pets.Where(x => person.Name == x.Owner.Name).DefaultIfEmpty()
【参考方案3】:
当遇到同样的问题时,我会收到以下错误消息:
连接子句中的其中一个表达式的类型不正确。调用“GroupJoin”时类型推断失败。
当我使用相同的属性名称时解决了,它起作用了。
(...)
join enderecoST in db.PessoaEnderecos on
new
CD_PESSOA = nf.CD_PESSOA_ST,
CD_ENDERECO_PESSOA = nf.CD_ENDERECO_PESSOA_ST
equals
new
enderecoST.CD_PESSOA,
enderecoST.CD_ENDERECO_PESSOA
into eST
(...)
【讨论】:
为此 +1。我盯着我的代码看了 15 分钟,试图理解为什么 2 个具有相同类型的匿名类不一样。然后我添加了明确的属性名称...【参考方案4】:这是 Fabrice(LINQ in Action 的作者)刚刚发布的一篇很好的博客文章,其中涵盖了我提出的问题中的材料。我把它放在这里供参考,因为问题的读者会发现这很有用。
Converting LINQ queries from query syntax to method/operator syntax
【讨论】:
【参考方案5】:使用 DefaultIfEmpty() 方法可以在 LINQ 中进行左连接。不过,我没有适合您的情况的确切语法...
实际上,我认为如果您只是在查询中将 pets 更改为 pets.DefaultIfEmpty() 它可能会起作用...
编辑:我真的不应该在很晚的时候回答问题......
【讨论】:
【参考方案6】:如果你真的有一个数据库,这是最简单的方法:
var lsPetOwners = ( from person in context.People
from pets in context.Pets
.Where(mypet => mypet.Owner == person.ID)
.DefaultIfEmpty()
select new OwnerName = person.Name, Pet = pets.Name
).ToList();
【讨论】:
以上是关于LINQ 内连接与左连接的主要内容,如果未能解决你的问题,请参考以下文章