Comment faire des jointures dans LINQ sur plusieurs champs en simple jointure

Je dois faire une requête LINQ2DataSet qui fait 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 cependant trouvé une solution adaptée (je peux append des contraintes supplémentaires à une clause where, mais cela est loin d’être une solution appropriée, ou utiliser cette solution, mais cela suppose une équijointure).

Est-il possible dans LINQ de se joindre à plusieurs champs dans une seule jointure?

MODIFIER

 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 que j’ai mentionnée en supposant une équijoinité ci-dessus.

EDIT supplémentaire

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

J’essaie cependant de comprendre les possibilités et les meilleures pratiques que j’ai / devrait utiliser avec LINQ. Je vais bientôt devoir faire une jointure de plage de dates avec un identifiant de table, et je devais préempter ce problème. Il semblerait que je doive append la plage de dates dans la clause where.

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

La solution avec le type anonyme devrait fonctionner correctement. LINQ ne peut représenter que des équijointes (avec des clauses de jointure, de toute façon), et c’est ce que vous avez dit exprimer de toute façon 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 faire.

EDIT: Répondre à la modification dans la question: oui, pour faire une jointure “plage de dates”, vous devez plutôt utiliser une clause where. Ils sont sémantiquement équivalents, donc il ne s’agit que des optimisations disponibles. Les équijointes 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 – pensez à la hashtable d’une clé à une séquence d’entrées correspondant à cette clé.

Faire cela avec des plages de dates est un peu plus difficile. Cependant, en fonction de ce que vous entendez exactement par une “plage de dates”, vous pouvez faire quelque chose de similaire – si vous prévoyez de créer des “bandes” de dates (par exemple une par an) telle que deux entrées même année (mais pas à la même date) devrait 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, correspondant à une plage comprise dans cette plage, qui serait mieux gérée avec une clause where (après une seconde clause). ) IMO. Vous pourriez faire de la magie particulièrement funky en ordonnant à un camp ou à un autre de trouver des correspondances plus efficacement, mais cela demanderait beaucoup de travail – je ne ferais que ce genre de chose après avoir vérifié si la performance pose problème.

 var result = from x in entity join y in entity2 on new { x.field1, x.field2 } equals new { y.field1, y.field2 } 
 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.

Juste pour compléter ceci avec une syntaxe de chaîne de méthode équivalente:

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

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

Je pense qu’une option plus lisible et 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 ().

 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 }; 

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

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

Si le nom du champ est différent 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}); 

Déclarez une classe (type) pour contenir les éléments que vous souhaitez rejoindre. Dans l’exemple ci-dessous, déclarez JoinElement

  public class **JoinElement** { public int? Id { get; set; } public ssortingng Name { get; set; } } results = from course in courseQueryable.AsQueryable() join agency in agencyQueryable.AsQueryable() on new **JoinElement**() { Id = course.CourseAgencyId, Name = course.CourseDeveloper } equals new **JoinElement**() { Id = agency.CourseAgencyId, Name = "D" } into temp1 

Comme une chaîne complète de méthode 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(); 
 from d in db.CourseDispatches join du in db.DispatchUsers on d.id equals du.dispatch_id join u in db.Users on du.user_id equals u.id join fr in db.Forumreports on (d.course_id + '_' + du.user_id) equals (fr.course_id + '_'+ fr.uid) 

cela fonctionne pour moi