LINQ to SQL: Mehrere Verknüpfungen in mehreren Spalten. Ist das möglich?

130

Gegeben:

Eine Tabelle TABLE_1mit den folgenden Spalten:

  • ID
  • ColumnA
  • ColumnB
  • ColumnC

Ich habe SQL - Abfrage , wo TABLE_1auf sich selbst schließt sich zweimal aus der Basis ColumnA, ColumnB, ColumnC. Die Abfrage könnte ungefähr so ​​aussehen:

Select t1.ID, t2.ID, t3.ID
  From TABLE_1 t1
  Left Join TABLE_1 t2 On
       t1.ColumnA = t2.ColumnA
   And t1.ColumnB = t2.ColumnB
   And t1.ColumnC = t2.ColumnC
  Left Join TABLE_1 t3 On
       t2.ColumnA = t3.ColumnA
   And t2.ColumnB = t3.ColumnB
   And t2.ColumnC = t3.ColumnC
... and query continues on etc.

Problem:

Diese Abfrage muss in LINQ neu geschrieben werden. Ich habe versucht, es zu versuchen:

var query =
    from t1 in myTABLE1List // List<TABLE_1>
    join t2 in myTABLE1List
      on t1.ColumnA equals t2.ColumnA
      && t1.ColumnB equals t2.ColumnA
    // ... and at this point intellisense is making it very obvious
    // I am doing something wrong :(

Wie schreibe ich meine Anfrage in LINQ? Was mache ich falsch?

aarona
quelle

Antworten:

240

Das Verknüpfen mehrerer Spalten in Linq mit SQL ist etwas anders.

var query =
    from t1 in myTABLE1List // List<TABLE_1>
    join t2 in myTABLE1List
      on new { t1.ColumnA, t1.ColumnB } equals new { t2.ColumnA, t2.ColumnB }
    ...

Sie müssen anonyme Typen nutzen und einen Typ für die mehreren Spalten erstellen, mit denen Sie vergleichen möchten.

Dies scheint zunächst verwirrend, aber sobald Sie sich mit der Art und Weise vertraut gemacht haben, wie SQL aus den Ausdrücken zusammengesetzt ist, ist dies viel sinnvoller. Unter dem Deckmantel wird dadurch die Art der Verknüpfung generiert, nach der Sie suchen.

BEARBEITEN Beispiel für zweiten Join basierend auf Kommentar hinzufügen.

var query =
    from t1 in myTABLE1List // List<TABLE_1>
    join t2 in myTABLE1List
      on new { A = t1.ColumnA, B = t1.ColumnB } equals new { A = t2.ColumnA, B = t2.ColumnB }
    join t3 in myTABLE1List
      on new { A = t2.ColumnA, B =  t2.ColumnB } equals new { A = t3.ColumnA, B = t3.ColumnB }
    ...
Quintin Robinson
quelle
4
Dies funktioniert hervorragend für zwei Joins. Ich brauche es, um mit DREI Joins zu arbeiten. Entschuldigung, der zweite Codeblock war etwas irreführend.
Aarona
46
Wenn Sie einen Compilerfehler bezüglich der Typinferenz erhalten, überprüfen Sie zwei Dinge: (1) sind die Typen gleich und (2) sind die Spaltennamen gleich. Der Namensteil ist ein Gotcha. Dieses Beispiel wird nicht kompiliert, selbst wenn alle Spalten Varchars sind join T2 in db.tbl2 on new { T1.firstName, T1.secondName } equals new { T2.colFirst, T2.colSecond }. Wenn Sie dies ändern, wird es jedoch kompiliertjoin T2 in db.tbl2 on new { N1 = T1.firstName, N2 = T1.secondName } equals new { N1 = T2.colFirst, N2 = T2.colSecond }
user2023861
4
Das Namensproblem kann beseitigt werden, indem von t1 in myTABLE1List t2 in myTABLE1List auf new {colA = t1.ColumnA, colB = t1.ColumnB} gleich new {colA = t2.ColumnA, colBBt2.ColumnB}
Baqer Naqvi
1
Bitte erlauben Sie mir, das Beispiel zu bearbeiten, da Zuweisungen an anonyme Eigenschaften
erforderlich waren
1
Hier stimmt etwas nicht ... mit LINQ. Ich kann an mehreren Tabellen beitreten, ich kann an mehreren Feldern beitreten ... ich kann es jedoch nicht für beide tun, wie das Beispiel hier zeigt. Nehmen wir also an, Sie haben nur einen Join in einem Feld. Und es folgt ein zweiter Join. Wenn Sie den ersten Join (oder beide) so ändern, dass nur new {x.field} gleich new {y.field} verwendet wird, liegt ein Compilerfehler vor. Funktionell haben Sie nichts geändert. Verwenden von .Net 4.6.1.
user2415376
12

In LINQ2SQL müssen Sie selten explizit beitreten, wenn Sie innere Verknüpfungen verwenden.

Wenn Sie ordnungsgemäße Fremdschlüsselbeziehungen in Ihrer Datenbank haben, erhalten Sie automatisch eine Beziehung im LINQ-Designer (wenn nicht, können Sie eine Beziehung manuell im Designer erstellen, obwohl Sie wirklich richtige Beziehungen in Ihrer Datenbank haben sollten).

Eltern-Kind-Beziehung

Dann können Sie einfach mit der "Punktnotation" auf verwandte Tabellen zugreifen.

var q = from child in context.Childs
        where child.Parent.col2 == 4
        select new
        {
            childCol1 = child.col1,
            parentCol1 = child.Parent.col1,
        };

generiert die Abfrage

SELECT [t0].[col1] AS [childCol1], [t1].[col1] AS [parentCol1]
FROM [dbo].[Child] AS [t0]
INNER JOIN [dbo].[Parent] AS [t1] ON ([t1].[col1] = [t0].[col1]) AND ([t1].[col2] = [t0].[col2])
WHERE [t1].[col2] = @p0
-- @p0: Input Int (Size = -1; Prec = 0; Scale = 0) [4]
-- Context: SqlProvider(Sql2008) Model: AttributedMetaModel Build: 4.0.30319.1

Meiner Meinung nach ist dies viel besser lesbar und ermöglicht es Ihnen, sich auf Ihre besonderen Bedingungen zu konzentrieren und nicht auf die eigentliche Mechanik der Verbindung.

Bearbeiten
Dies gilt natürlich nur, wenn Sie sich der Linie mit unserem Datenbankmodell anschließen möchten. Wenn Sie "außerhalb des Modells" beitreten möchten, müssen Sie auf manuelle Verknüpfungen zurückgreifen, wie in der Antwort von Quintin Robinson

Albin Sunnanbo
quelle
11

Title_Authors ist eine Suche nach zwei Dingen, die sich zu einem bestimmten Zeitpunkt verbinden und die Verkettung fortsetzen

        DataClasses1DataContext db = new DataClasses1DataContext();
        var queryresults = from a in db.Authors                                          
                    join ba in db.Title_Authors                           
                    on a.Au_ID equals ba.Au_ID into idAuthor
                    from c in idAuthor
                    join t in db.Titles  
                    on c.ISBN equals t.ISBN 
                    select new { Author = a.Author1,Title= t.Title1 };

        foreach (var item in queryresults)
        {
            MessageBox.Show(item.Author);
            MessageBox.Show(item.Title);
            return;
        }
BionicCyborg
quelle
10

Sie können auch verwenden:

var query =
    from t1 in myTABLE1List 
    join t2 in myTABLE1List
      on new { ColA=t1.ColumnA, ColB=t1.ColumnB } equals new { ColA=t2.ColumnA, ColB=t2.ColumnB }
    join t3 in myTABLE1List
      on new {ColC=t2.ColumnA, ColD=t2.ColumnB } equals new { ColC=t3.ColumnA, ColD=t3.ColumnB }
Baqer Naqvi
quelle
3
ÄHHH!! Das funktioniert! Der entscheidende Unterschied besteht darin, dass Sie den Teil "ColA =" ausführen müssen, damit im anderen Join dasselbe Feld angezeigt wird. Ich habe das jahrelang nicht gemacht, aber ich brauchte auch nur einen Join auf mehreren Feldern. Aber jetzt brauche ich mehr und es FUNKTIONIERT NUR, wenn ich den Feldern wie in diesem Beispiel einen Variablennamen zuweise.
user2415376
3

Ich möchte ein weiteres Beispiel geben, in dem mehrere (3) Verknüpfungen verwendet werden.

 DataClasses1DataContext ctx = new DataClasses1DataContext();

        var Owners = ctx.OwnerMasters;
        var Category = ctx.CategoryMasters;
        var Status = ctx.StatusMasters;
        var Tasks = ctx.TaskMasters;

        var xyz = from t in Tasks
                  join c in Category
                  on t.TaskCategory equals c.CategoryID
                  join s in Status
                  on t.TaskStatus equals s.StatusID
                  join o in Owners
                  on t.TaskOwner equals o.OwnerID
                  select new
                  {
                      t.TaskID,
                      t.TaskShortDescription,
                      c.CategoryName,
                      s.StatusName,
                      o.OwnerName
                  };
user3477428
quelle
9
Nicht dasselbe - bei der Frage geht es darum, Tabellen basierend auf jeweils mehreren Spalten zu verbinden und nicht mehrere Tabellen basierend auf jeweils einer Spalte zu verbinden.
Isochronous
1

Sie können auch beitreten, wenn die Anzahl der Spalten in beiden Tabellen nicht gleich ist, und statische Werte der Tabellenspalte zuordnen

from t1 in Table1 
join t2 in Table2 
on new {X = t1.Column1, Y = 0 } on new {X = t2.Column1, Y = t2.Column2 }
select new {t1, t2}
Ankit Arya
quelle
-6

Meiner Meinung nach ist dies der einfachste Weg, zwei Tabellen mit mehreren Feldern zu verbinden:

from a in Table1 join b in Table2    
       on (a.Field1.ToString() + "&" + a.Field2.ToString())     
       equals  (b.Field1.ToString() + "&" + b.Field2.ToString())  
     select a
Praveen Kumar
quelle
In SQL wäre dies erheblich langsamer als das separate Verknüpfen jeder Spalte (obwohl es immer noch ziemlich schnell wäre, wenn das Dataset nicht groß wäre). Vermutlich würde linq das offensichtliche SQL generieren. Denken Sie also an die Leistung, wenn Sie diese Lösung verwenden.
EGP
-10

Sie können Ihre Anfrage so schreiben.

var query = from t1 in myTABLE1List // List<TABLE_1>
            join t2 in myTABLE1List
               on t1.ColumnA equals t2.ColumnA
               and t1.ColumnB equals t2.ColumnA

Wenn Sie Ihre Spalte mit mehreren Spalten vergleichen möchten.

Anvesh
quelle
1
@ user658720 Willkommen bei StackOverFlow :). Ich würde vorschlagen, dass Sie Ihren Code so formatieren, dass er leichter zu lesen ist. Sie können den Text auswählen und im Editor auf die Codeschaltfläche klicken.
Aarona