[c#] LINQ Inner-Join vs Left-Join

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

This question is related to c# .net linq left-join

The answer is


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

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

(...)


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...


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


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

Examples related to c#

How can I convert this one line of ActionScript to C#? Microsoft Advertising SDK doesn't deliverer ads How to use a global array in C#? How to correctly write async method? C# - insert values from file into two arrays Uploading into folder in FTP? Are these methods thread safe? dotnet ef not found in .NET Core 3 HTTP Error 500.30 - ANCM In-Process Start Failure Best way to "push" into C# array

Examples related to .net

You must add a reference to assembly 'netstandard, Version=2.0.0.0 How to use Bootstrap 4 in ASP.NET Core No authenticationScheme was specified, and there was no DefaultChallengeScheme found with default authentification and custom authorization .net Core 2.0 - Package was restored using .NetFramework 4.6.1 instead of target framework .netCore 2.0. The package may not be fully compatible Update .NET web service to use TLS 1.2 EF Core add-migration Build Failed What is the difference between .NET Core and .NET Standard Class Library project types? Visual Studio 2017 - Could not load file or assembly 'System.Runtime, Version=4.1.0.0' or one of its dependencies Nuget connection attempt failed "Unable to load the service index for source" Token based authentication in Web API without any user interface

Examples related to linq

Async await in linq select How to resolve Value cannot be null. Parameter name: source in linq? What does Include() do in LINQ? Selecting multiple columns with linq query and lambda expression System.Collections.Generic.List does not contain a definition for 'Select' lambda expression join multiple tables with select and where clause LINQ select one field from list of DTO objects to array The model backing the 'ApplicationDbContext' context has changed since the database was created Check if two lists are equal Why is this error, 'Sequence contains no elements', happening?

Examples related to left-join

MySQL select rows where left join is null How to return rows from left table not found in right table? How to specify names of columns for x and y when joining in dplyr? Select rows which are not present in other table SQL LEFT-JOIN on 2 fields for MySQL Combine two pandas Data Frames (join on a common column) SQL LEFT JOIN Subquery Alias How to use mysql JOIN without ON condition? LEFT JOIN only first row MySQL - sum column value(s) based on row from the same table