LINQ内部连接与左连接

42

我正在尝试使用扩展语法在LINQ上创建左连接以连接两个列表。以下内容来自Microsoft帮助文档,但我已修改以显示pets列表中没有元素的情况。最终我得到的是一个由0个元素组成的列表。我认为这是因为进行了内部连接。我想要的结果是一个由3个元素(3个Person对象)组成的列表,并且对于缺少的元素填充null数据,即左连接。这种情况是否可能?

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();
6个回答

76

我认为如果你想使用扩展方法,你需要使用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();

1
哇嗬 :) 正是我在寻找的! - Ekaterina
我不知道你可以通过在查询方法周围加括号来获得.ToList(),谢谢! - Haroon
3
请不要将LINQ声明式查询语法称为"LINQ语法",它们都是"LINQ语法"。正确的命名应该是"查询语法"与"方法语法"。http://msdn.microsoft.com/en-us/library/bb397947.aspx - Pluc
3
后者的不当命名为“Yoda风格语法”。 - sshine

17
你需要将连接的对象放入一个集合中,然后像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 - 非常有用的信息。 - Guy
我认为你可以用这一行代码替换掉两行:join pet...from ownedPet...,新的代码如下:from pet in pets.Where(x => person.Name == x.Owner.Name).DefaultIfEmpty() - Jim Rhodes

5

当我遇到同样的问题时,我看到了以下错误信息:

连接子句中一个表达式的类型不正确。在调用“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

(...)


我盯着我的代码看了15分钟,试图理解为什么具有相同类型的2个匿名类不同。然后我添加了显式属性名称... - drdwilcox

3

2
在LINQ中,使用DefaultIfEmpty()方法可以实现左连接。不过,我没有你这种情况的确切语法...实际上,如果您只是在查询中将pets更改为pets.DefaultIfEmpty(),它可能会起作用...编辑:晚上回答问题真的不应该...

0
如果您实际上拥有一个数据库,这是最简单的方法:
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();

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