LINQ 内连接与左连接

发布于 2024-07-14 02:30:21 字数 1214 浏览 7 评论 0原文

使用扩展语法,我尝试使用 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();

Using extension syntax I'm trying to create a left-join using LINQ on two lists that I have. The following is from the Microsoft help but I've modified it to show that the pets list has no elements. What I'm ending up with is a list of 0 elements. I assume that this is because an inner-join is taking place. What I want to end up with is a list of 3 elements (the 3 Person objects) with null data filled in for the missing elements. i.e. a Left-Join. Is this possible?

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();

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

尐偏执 2024-07-21 02:30:21

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

I think if you want to use extension methods you need to use the 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();

You may have to play around with the selection expression. I'm not sure it would give you want you want in the case where you have a 1-to-many relationship.

I think it's a little easier with the LINQ Query syntax

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();
━╋う一瞬間旳綻放 2024-07-21 02:30:21

您需要将连接的对象放入一个集合中,然后应用 DefaultIfEmpty,如 JPunyon 所说:

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

You need to get the joined objects into a set and then apply DefaultIfEmpty as JPunyon said:

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 ) );
}

Outputs:

Adams, Terry              has Barley
Hedlund, Magnus           has
Weiss, Charlotte          has
偏爱自由 2024-07-21 02:30:21

当遇到同样的问题时,我出现以下错误消息:

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

(...)

I the following error message when faced this same problem:

The type of one of the expressions in the join clause is incorrect. Type inference failed in the call to 'GroupJoin'.

Solved when I used the same property name, it worked.

(...)

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

(...)

挽袖吟 2024-07-21 02:30:21

这是 Fabrice(《LINQ in Action》的作者)刚刚发布的一篇很好的博客文章,其中涵盖了我提出的问题中的材料。 我将其放在这里供参考,因为问题的读者会发现这很有用。

将 LINQ 查询从查询​​语法转换为方法/运算符语法

Here's a good blog post that's just been posted by Fabrice (author of LINQ in Action) which covers the material in the question that I asked. I'm putting it here for reference as readers of the question will find this useful.

Converting LINQ queries from query syntax to method/operator syntax

新雨望断虹 2024-07-21 02:30:21

LINQ 中的左连接可以使用 DefaultIfEmpty() 方法实现。 不过,我没有适合您情况的确切语法...

实际上,我认为如果您只是在查询中将 pets 更改为 pets.DefaultIfEmpty() ,它可能会起作用...

编辑:我真的不应该在迟到时回答问题...

Left joins in LINQ are possible with the DefaultIfEmpty() method. I don't have the exact syntax for your case though...

Actually I think if you just change pets to pets.DefaultIfEmpty() in the query it might work...

EDIT: I really shouldn't answer things when its late...

婴鹅 2024-07-21 02:30:21

如果您确实有数据库,这是最简单的方法:

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();

If you actually have a database, this is the most-simple way:

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();
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文