web-dev-qa-db-fra.com

LINQ Inner-Join vs Left-Join

Utilisation de la syntaxe d'extension J'essaie de créer une jointure à gauche à l'aide de LINQ sur deux listes que j'ai. Ce qui suit provient de l'aide de Microsoft, mais je l'ai modifié pour montrer que la liste des animaux de compagnie ne contient aucun élément. Je termine avec une liste de 0 éléments. Je suppose que c'est parce qu'il y a une jointure interne. Ce que je veux finir est une liste de 3 éléments (les objets 3 personnes) avec des données nulles renseignées pour les éléments manquants. c'est-à-dire une jointure à gauche. Est-ce 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();
41
Guy

Je pense que si vous voulez utiliser des méthodes d'extension, vous devez utiliser le 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();

Vous devrez peut-être jouer avec l'expression de sélection. Je ne suis pas sûr que cela vous donnerait ce que vous voulez dans le cas où vous avez une relation un à plusieurs.

Je pense que c'est un peu plus facile avec la syntaxe LINQ Query

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

Vous devez obtenir les objets joints dans un jeu, puis appliquer DefaultIfEmpty comme indiqué par 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 ) );
}

Les sorties:

Adams, Terry              has Barley
Hedlund, Magnus           has
Weiss, Charlotte          has
15
Gishu

Je le message d'erreur suivant face à ce même problème:

Le type d'une des expressions dans la clause join est incorrect. L'inférence de type a échoué lors de l'appel à 'GroupJoin'.  

Résolu lorsque j'ai utilisé le même nom de propriété, cela a fonctionné.

(...)

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

(...)

5
João Vieira

Voici un bon article de blog qui vient d'être posté par Fabrice (auteur de LINQ in Action) qui couvre le contenu de la question que j'ai posée. Je le mets ici pour référence, car les lecteurs de la question trouveront cela utile.

Conversion des requêtes LINQ de syntaxe de requête en syntaxe de méthode/opérateur

3
Guy

Les jointures à gauche dans LINQ sont possibles avec la méthode DefaultIfEmpty (). Je n'ai cependant pas la syntaxe exacte pour votre cas ...

En fait, je pense que si vous changez simplement d'animaux de compagnie en animaux de compagnie.

EDIT: Je ne devrais vraiment pas répondre aux questions quand il est tard ...

2
Jason Punyon

Si vous avez réellement une base de données, voici le moyen le plus simple:

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();
0
Stefan Steiger