LINQ Inner-Join vs gauche-Join
Question
En utilisant la syntaxe d'extension, je suis en train de créer une gauche rejoindre LINQ sur deux listes que j'ai. Ce qui suit est de l'aide de Microsoft, mais je l'ai modifié pour montrer que la liste des animaux n'a pas d'éléments. Ce que je veux finir avec une liste de 0 éléments. Je suppose que cela est parce qu'un intérieur jointure est en cours. Ce que je veux retrouver avec une liste de 3 éléments (les 3 objets de personne) avec des données nulles remplies pour les éléments manquants. à-dire une gauche d'inscription. 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();
La solution
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 ça vous voulez que vous voulez donner dans le cas où vous avez 1 à plusieurs.
Je pense qu'il est un peu plus facile avec la syntaxe de requête 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();
Autres conseils
Vous devez obtenir les objets réunis en un ensemble, puis appliquez DefaultIfEmpty comme JPunyon dit:
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 ) );
}
Sorties:
Adams, Terry has Barley
Hedlund, Magnus has
Weiss, Charlotte has
Je le message d'erreur suivant lorsqu'ils sont confrontés à ce même problème:
dans la clause de jointure Le type de l'une des expressions est incorrecte. L'inférence de type a échoué dans l'appel à 'GroupJoin'.
Résolu quand j'utilisé le même nom de la propriété, il a travaillé.
(...)
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
(...)
Voici un bon blog qui vient d'être publié par Fabrice (auteur de LINQ en action) qui couvre la matière dans la question que je posais. Je mets ici pour référence que les lecteurs de la question trouveront cela utile.
Conversion de requêtes LINQ de syntaxe de la requête à la méthode / syntaxe opérateur
gauche se joint à LINQ sont possibles avec le procédé DefaultIfEmpty (). Je n'ai pas la syntaxe exacte pour votre cas si ...
En fait, je pense que si vous venez de changer les animaux de compagnie à pets.DefaultIfEmpty () dans la requête, il pourrait fonctionner ...
EDIT: Je ne devrais pas répondre à des choses quand sa fin ...
Si vous avez fait une base de données, c'est la façon la 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();