JOINTURE EXTERNE GAUCHE dans LINQ to objects
Considérons le code suivant.
Ville et CitPlace sont rejoints par CityCode.
Ce que je veux faire est d'effectuer une JOINTURE EXTERNE GAUCHE entre CityPlace et de la Ville.
City[] cities = new City[]{
new City{CityCode="0771",CityName="Raipur",CityPopulation="BIG"},
new City{CityCode="0751",CityName="Gwalior",CityPopulation="MEDIUM"},
new City{CityCode="0755",CityName="Bhopal",CityPopulation="BIG"},
new City{CityCode="022",CityName="Mumbai",CityPopulation="BIG"},
};
CityPlace[] places = new CityPlace[]{
new CityPlace{CityCode="0771",Place="Shankar Nagar"},
new CityPlace{CityCode="0771",Place="Pandari"},
new CityPlace{CityCode="0771",Place="Energy Park"},
new CityPlace{CityCode="0751",Place="Baadaa"},
new CityPlace{CityCode="0751",Place="Nai Sadak"},
new CityPlace{CityCode="0751",Place="Jayendraganj"},
new CityPlace{CityCode="0751",Place="Vinay Nagar"},
new CityPlace{CityCode="0755",Place="Idgah Hills"},
new CityPlace{CityCode="022",Place="Parel"},
new CityPlace{CityCode="022",Place="Haaji Ali"},
new CityPlace{CityCode="022",Place="Girgaon Beach"},
new CityPlace{CityCode="0783",Place="Railway Station"}};
Ce que j'ai fait est
var res = places.GroupJoin(cities,
p1=>p1.CityCode,
c1=>c1.CityCode,
(p2,c2s)=>new {Place=p2.Place,
CityName=c2s.Count()==0 ? "NO NAME"
: c2s.First().CityName });
foreach(var v in res)
Console.WriteLine(v);
Est-ce que la norme ou il est rapidement et la solution sale?
Vous devez vous connecter pour publier un commentaire.
Dans votre cas, vous ne regroupez pas les enregistrements, afin de ne pas utiliser votre solution. vous pouvez utiliser la solution de ScottS ou utilisez la requête ci-dessous.
Votre propre réponse est bien, mais ce n'est pas très élégant. Donc, oui, c'est un peu sale. Il y a un niveau moyen de faire une jointure externe gauche, qui s'occupe de votre exemple et serait en mesure de gérer les cas où il y a les villes en double. Votre exemple ne peut pas gérer les villes en double parce que tous les doublons sont ignorés lorsque vous sélectionnez
c2s.First()
.La norme de gauche joindre les étapes sont les suivantes:
Votre GroupJoin est l'aplatissement de la hiérarchie en une seule étape, en ignorant tout, sauf le premier correspondant à la ville. C'est ce qui est sale à ce sujet. Si vous essayez d'utiliser ce code dans le sens inverse en prenant les villes de gauche et de se joindre à eux sur les lieux, vous n'aurez qu'une seule place par la ville de! C'est évidemment mauvais. Il est préférable d'apprendre à faire une jointure gauche la bonne façon, et puis il le sera toujours.
La SelectMany à l'étape 2 est réellement en option si vous souhaitez conserver la hiérarchie et puis imbriquer les boucles foreach pour les afficher, mais je vais supposer que vous souhaitez afficher les données dans une table à plat format.
Si vous voulez juste pour voir la réponse à votre problème concret, faites défiler jusqu'à "des Villes et des Lieux" de la rubrique ci-dessous, mais d'abord, voici un exemple complet à l'aide de deux simples tableaux de chaîne.
Abstraite Exemple avec Explication Complète
Voici un exemple complet à l'aide de deux tableaux de lettres à la place de votre code. Je voulais montrer un exemple simple d'abord. Vous pouvez les copier et les coller dans LINQPad et à définir la Langue "C# Consolidés", et l'exécuter pour vous-même si vous le souhaitez. Je très recommander LINQPad comme un outil pour tester toutes sortes de code, pas seulement LINQ. Alternativement, vous pouvez également créer une application console dans Visual Studio.
Voici le code sans trop de commentaires. Ci-dessous c'est une version qui est abondamment commentés. Vous pouvez sauter à la, si vous voulez savoir exactement ce que chaque paramètre moyens.
Voici le résultat, qui doit être assez évident, car nous savons tous ce qu'est une jointure gauche est censé faire.
Lourdement version annotée:
De nouveau, la sortie de la référence:
Au-dessus de l'utilisation de LINQ est souvent appelé la "méthode de la chaîne". Vous prenez des collections et de la chaîne d'ensemble des méthodes pour obtenir ce que vous voulez. (La plupart du temps vous n'avez pas utiliser des variables pour stocker les expressions individuelles. Vous venez de faire GroupJoin(...).SelectMany(...), c'est pourquoi elle est appelée "méthode de la chaîne". Il est très détaillé et explicite, et prend beaucoup de temps pour écrire.
Au lieu de cela, nous pouvons utiliser ce qu'on appelle une "compréhension", de la requête "compréhension" ou "LINQ compréhension". La compréhension est un ancien ordinateur de la science terme à partir des années 1970, qui honnêtement n'a pas beaucoup de sens pour la plupart des gens. Au lieu de cela les gens les appellent "les requêtes LINQ", ou "expressions LINQ", mais ceux théoriquement s'appliquer à la méthode des chaînes de bien, parce que dans les deux cas, vous êtes la construction d'une arborescence d'expression. (Expression arbres sont en dehors de la portée de ce tutoriel.) Une LINQ la compréhension est une syntaxe de type SQL pour l'écriture de LINQ, mais ce n'est pas SQL! Il n'a rien à voir avec SQL réel. Voici le même code écrit comme une requête de compréhension:
Cela permettra de compiler pour le exacte même code comme dans l'exemple ci-dessus, sauf que le paramètre nommé "groupJoinItem" dans le SelectMany sera nommé quelque chose comme "temp0", car ce paramètre n'est pas explicitement existe pas dans la compréhension de la version de ce code.
Je pense que vous pouvez comprendre comment beaucoup plus simple de cette version du code. J'ai toujours utiliser cette syntaxe lors d'une jointure externe gauche. Je n'ai jamais utiliser GroupJoin avec SelectMany. Cependant, à première vue, il fait très peu de sens. Un
join
suivie par uninto
crée un GroupJoin. Vous devez d'abord savoir ce, et pourquoi vous voulez cette. Ensuite, la deuxièmefrom
indique une SelectMany, ce qui n'est pas évidente. Lorsque vous avez deuxfrom
mots-clés vous sont effectivement la création d'une jointure croisée (produit cartésien), qui est ce SelectMany est en train de faire. (En quelque sorte.)Par exemple, cette requête:
donnerait:
C'est une base de jointure croisée.
Donc, revenons à notre gauche d'origine joindre requête LINQ: La première
from
de la requête est le groupe de la rejoindre, et la deuxièmefrom
exprime une jointure croisée entre chaque groupJoinItem et sa propre collection de la correspondance de droit lettres. C'est un peu comme ceci:En fait, nous avons effectivement pu l'écrire en tant que tel!
Que selectMany exprime la suivante: "pour chaque élément dans groupJoin, croix joindre à son propre MatchingRightLetters des biens, et de les enchaîner tous les résultats ensemble." Cela donne exactement le même résultat que l'un de nos gauche joindre le code ci-dessus.
C'est sans doute trop beaucoup d'une explication à cette simple question, mais je n'aime pas de culte du cargo de programmation (google). Vous devez savoir exactement ce que votre code est en train de faire, et pourquoi, sinon vous ne serez pas en mesure de s'attaquer à des problèmes plus complexes.
Des villes et des Lieux
Alors, voici la méthode de la chaîne de version de votre code. C'est tout un programme afin que les gens puissent l'exécuter si ils le souhaitent (Utiliser le "Programme C#" type de langue de LINQPad ou de faire une console application avec Visual Studio ou le Compilateur C#.)
Voici le résultat:
Avis que le DefaultIfEmpty va renvoyer une nouvelle instance de la Ville proprement dite classe et pas seulement une chaîne de caractères. C'est parce que nous rejoignons le CityPlaces à la Ville des objets, pas des chaînes de caractères. Vous pouvez utiliser
DefaultIfEmpty()
au lieu de cela, avec aucun paramètre, et vous obtenez unnull
de la Ville de "la Gare", mais alors il faudrait vérifier, pour les valeurs null dans votre boucle foreach avant l'appel de la paire.Ville.CityName. C'est une question de préférence personnelle.Voici le même programme à l'aide d'une requête de la compréhension: l'
En tant qu'utilisateur SQL, j'ai beaucoup préfèrent la requête de compréhension de la version. Il est beaucoup plus facile pour quelqu'un d'autre de lire les intention du code une fois que vous savez ce que chacun des éléments de la requête ne.
Bonne programmation!
Voici une requête linq version
Je pense que l'utilisation de DefaultIfEmpty() rend un peu plus clair.
Dans l'ensemble, je trouve les jointures externes dans linq vachement à confusion. C'est l'un des rares endroits où je trouve des requêtes SQL considérablement supérieure.