web-dev-qa-db-fra.com

Comment faire des jointures dans LINQ sur plusieurs champs dans une jointure unique

Je dois effectuer une requête LINQ2DataSet qui effectue une jointure sur plusieurs champs (comme

var result = from x in entity
join y in entity2 
       on x.field1 = y.field1 
and 
          x.field2 = y.field2

J'ai encore trouvé une solution appropriée (je peux ajouter les contraintes supplémentaires à une clause where, mais c'est loin d'être une solution appropriée, ou utiliser this solution, mais cela suppose une équijointure).

Est-il possible dans LINQ de joindre plusieurs champs en une seule?

EDIT

var result = from x in entity
             join y in entity2
             on new { x.field1, x.field2 } equals new { y.field1, y.field2 }

est la solution à laquelle j'ai fait référence en supposant l'équijoin ci-dessus.

En outre EDIT

Pour répondre à la critique selon laquelle mon exemple initial était une équijointure, je reconnais que, actuellement, mon exigence est une équijointure et j'ai déjà utilisé la solution mentionnée ci-dessus.

Cependant, j'essaie de comprendre quelles sont les possibilités et les meilleures pratiques que j'ai/devrais utiliser avec LINQ. Je vais devoir faire bientôt une jointure de requête de plage de dates avec un ID de table, et je ne faisais que préempter ce problème. Il semble que je devrai ajouter la plage de dates dans la clause where.

Merci, comme toujours, pour toutes les suggestions et commentaires donnés

232
johnc

La solution avec le type anonyme devrait fonctionner correctement. LINQ peut ne représenter que des équijoins (avec des clauses de jointure, de toute façon), et c'est bien ce que vous avez dit vouloir exprimer quand même en fonction de votre requête initiale.

Si vous n'aimez pas la version avec le type anonyme pour une raison spécifique, vous devez expliquer cette raison.

Si vous voulez faire autre chose que ce que vous aviez initialement demandé, donnez un exemple de ce que vous voulez vraiment .

EDIT: En réponse à la modification dans la question: oui, pour faire une jointure "de plage de dates", vous devez utiliser une clause where à la place. Ils sont vraiment sémantiquement équivalents, alors il ne s'agit que d'optimisations disponibles. Les équijoins fournissent une optimisation simple (dans LINQ to Objects, qui inclut LINQ to DataSets) en créant une recherche basée sur la séquence interne. Considérez-la comme une table de hachage allant d'une clé à une séquence d'entrées correspondant à cette clé.

Faire cela avec les plages de dates est un peu plus difficile. Toutefois, en fonction de ce que vous entendez par "joindre la plage de dates", vous pourrez peut-être faire quelque chose de similaire - si vous prévoyez de créer " "bandes" de dates (par exemple une par an) telles que deux entrées qui se produisent dans la même année (mais pas à la même date) doivent correspondre, alors vous pouvez le faire simplement en utilisant cette bande comme clé. Si c'est plus compliqué, par exemple un côté de la jointure fournit une plage, et l’autre côté de la jointure fournit une date unique, qui correspond si elle se situe dans cette plage, qui serait mieux gérée avec une clause where (après une seconde from clause) IMO. Vous pourriez faire de la magie particulièrement funky en ordonnant à l'un ou l'autre des camps de trouver des matches plus efficacement, mais ce serait beaucoup de travail - je ne le ferais que si je vérifiais si la performance posait problème.

87
Jon Skeet
var result = from x in entity
   join y in entity2 on new { x.field1, x.field2 } equals new { y.field1, y.field2 }
124
KristoferA
var result = from x in entity1
             join y in entity2
             on new { X1= x.field1, X2= x.field2 } equals new { X1=y.field1, X2= y.field2 }

Vous devez le faire si les noms de colonne sont différents dans deux entités.

70
RealNapster

Pour compléter ceci avec une syntaxe de chaîne de méthodes équivalente:

entity.Join(entity2, x => new {x.Field1, x.Field2},
                     y => new {y.Field1, y.Field2}, (x, y) => x);

Tandis que le dernier argument (x, y) => x est ce que vous sélectionnez (dans le cas ci-dessus, nous sélectionnons x).

48
niieani

Je pense qu'une option plus lisible et plus flexible consiste à utiliser la fonction Where:

var result = from x in entity1
             from y in entity2
                 .Where(y => y.field1 == x.field1 && y.field2 == x.field2)

Cela permet également de passer facilement de la jointure interne à la jointure gauche en ajoutant .DefaultIfEmpty ().

29
Alexei
var result = from x in entity
             join y in entity2
             on new { X1= x.field1, X2= x.field2 } equals new { X1=y.field1, X2= y.field2 }
             select new 
             {
               /// Columns
              };
9
user3966657

vous pourriez faire quelque chose comme (ci-dessous)

var query = from p in context.T1

        join q in context.T2

        on

        new { p.Col1, p.Col2 }

        equals

         new { q.Col1, q.Col2 }

        select new {p...., q......};
8
Perpetualcoder

En utilisant l'opérateur de jointure, vous ne pouvez effectuer que des équijoins. D'autres types de jointures peuvent être construits à l'aide d'autres opérateurs. Je ne suis pas sûr si la jointure exacte que vous essayez de faire serait plus facile en utilisant ces méthodes ou en modifiant la clause where. La documentation sur la clause join peut être trouvée ici . MSDN a un article sur les opérations de jointure avec plusieurs liens vers des exemples d'autres jointures.

7
tvanfosson

Si les noms de champs sont différents dans les entités

var result = from x in entity
   join y in entity2 on 
          new {
                field1=   x.field1,
               field2 =  x.field2 
             } 
          equals
         new { 
                field1= y.field1,
                field2=  y.myfield
              }
select new {x,y});
3
Mahesh

En tant que chaîne de méthode complète qui ressemblerait à ceci:

lista.SelectMany(a => listb.Where(xi => b.Id == a.Id && b.Total != a.Total),
                (a, b) => new ResultItem
                {
                    Id = a.Id,
                    ATotal = a.Total,
                    BTotal = b.Total
                }).ToList();
2
Adam Garner