2009-07-07 6 views
5

Il y a beaucoup de questions sur SO déjà à propos des jointures à gauche dans Linq, et celles que j'ai regardées toutes utilisent le mot clé join pour atteindre la fin désirée.A rejoint Linq?

Cela n'a aucun sens pour moi. Disons que j'ai les tables Customer et Invoice, liées par une clé étrangère CustomerID sur Invoice. Maintenant, je veux lancer un rapport contenant des informations sur les clients, plus toutes les factures. SQL serait:

select c.*, i.* 
    from Customer c 
    left join Invoice i on c.ID = i.CustomerID 

D'après ce que j'ai vu des réponses sur le SO, les gens sont la plupart du temps ce qui suggère:

var q = from c in Customers 
     join i in Invoices.DefaultIfEmpty() on c.ID equals i.CustomerID 
     select new { c, i }; 

Je ne comprends vraiment pas comment cela peut être la seule façon. La relation entre Customer et Invoice est déjà définie par les classes LinqToSQL; Pourquoi devrais-je le répéter pour la clause join? Si je voulais une jointure interne il aurait simplement été:

var q = from c in Customers 
     from i in c.Invoices 
     select new { c, i }; 

sans spécifier les champs joints!

J'ai essayé:

var q = from c in Customers 
     from i in c.Invoices.DefaultIfEmpty() 
     select new { c, i }; 

mais m'a donné le même résultat que si elle était une jointure interne.

N'y a-t-il pas une meilleure façon de procéder?

Répondre

5

De quoi parlez-vous? Ce from i in c.Invoice.DefaultIfEmpty() est exactement une jointure à gauche.

 List<string> strings = new List<string>() { "Foo", "" }; 

     var q = from s in strings 
       from c in s.DefaultIfEmpty() 
       select new { s, c }; 

     foreach (var x in q) 
     { 
      Console.WriteLine("ValueOfStringIs|{0}| ValueOfCharIs|{1}|", 
       x.s, 
       (int)x.c); 
     } 

Ce test produit:

ValueOfStringIs|Foo| ValueOfCharIs|70| 
ValueOfStringIs|Foo| ValueOfCharIs|111| 
ValueOfStringIs|Foo| ValueOfCharIs|111| 
ValueOfStringIs|| ValueOfCharIs|0| 
+1

Eh bien soufflez-moi - vous avez raison! Maintenant, pourquoi ai-je pensé que ça ne fonctionnait pas ...? OK, humblement je redescends ... cette question résultait de mon propre malentendu. MERCI! :) –

2

Vous pouvez probablement utiliser le mot-clé 'dans'.

Example

+0

Merci, mais cela ne répond pas vraiment à ma question ... est-il pas une meilleure façon, en profitant du fait que la relation est déjà définie? –

6

Bien que la relation est déjà définie (dans la base de données et dans le balisage .dbml) le moteur d'exécution ne peut pas déterminer automatiquement si elle doit utiliser cette relation. Qu'arrive-t-il s'il existe deux relations dans le modèle objet (la personne a des parents et des enfants, les deux relations avec d'autres instances de personne). Bien que les cas puissent être spéciaux, cela rendrait le système plus complexe (donc plus de bugs). Souvenez-vous en SQL que vous répéteriez la spécification de la relation. Rappelez-vous que les index et les clés sont un détail d'implémentation et ne font pas partie de l'algèbre relationnelle qui sous-tend le modèle de relation.

Si vous voulez un LEFT OUTER JOIN alors vous devez utiliser "into":

from c in Customers 
join i in Invoices on i.CustomerId equals c.CustomerId into inv 
... 

et inv aura le type IEnumerable<Invoivce>, peut-être sans cas.

+0

+1 Bonne réponse, mais vous manquez toujours mon point.La facture a spécifiquement une relation "Clients" définie, et je veux faire usage de cette relation: "c.Invoices", pas seulement "Factures". Y'a-t'il un quelconque moyen d'y arriver? –

+0

@Shaul: Ensuite, utilisez simplement c.Factures dans l'expression. Si vous voulez un identifiant différent, utilisez une clause let. – Richard

Questions connexes