LINQ do SQL: wiele złączeń na wielu kolumnach. Czy to możliwe?

Podane:

Tabela o nazwie TABLE_1 z następującymi kolumnami:

  • ID
  • ColumnA
  • ColumnB
  • ColumnC

Mam zapytanie SQL gdzie TABLE_1 łączy się na siebie dwa razy na podstawie ColumnA, ColumnB, ColumnC. Zapytanie może wyglądać mniej więcej tak:

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:

Chcę, aby to zapytanie zostało przepisane w LINQ. Próbowałem to zrobić:

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 :(

Jak napisać zapytanie w LINQ? Co robię źle?

Author: DJTripleThreat, 2011-03-15

8 answers

Łączenie wielu kolumn w Linq do SQL jest trochę inne.

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

Musisz skorzystać z anonimowych typów i skomponować typ dla wielu kolumn, z którymi chcesz porównać.

Na początku wydaje się to mylące, ale po zapoznaniu się ze sposobem, w jaki składa się SQL z wyrażeń, będzie to miało o wiele więcej sensu, pod pokrywami wygeneruje to typ połączenia, którego szukasz.

EDIT dodawanie przykładu dla drugiego połączenia na podstawie komentarza.

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 }
    ...
 195
Author: Quintin Robinson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-07-24 07:01:48

W LINQ2SQL rzadko trzeba dołączać jawnie podczas używania złączy wewnętrznych.

Jeśli masz odpowiednie relacje z kluczami obcymi w bazie danych, automatycznie otrzymasz relację w LINQ designer (jeśli nie, możesz utworzyć relację ręcznie w designerze, chociaż naprawdę powinieneś mieć odpowiednie relacje w bazie danych)

relacja rodzic-dziecko

Następnie możesz po prostu uzyskać dostęp do powiązanych tabel z "notacją kropkową"

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

Wygeneruje zapytanie

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

W moim opinia jest o wiele bardziej czytelna i pozwala skoncentrować się na specjalnych warunkach, a nie na rzeczywistej mechanice połączenia.

Edit
Ma to oczywiście zastosowanie tylko wtedy,gdy chcesz dołączyć do naszego modelu bazy danych. Jeśli chcesz dołączyć "poza modelem" musisz uciekać się do ręcznych złączeń jak w odpowiedź z Quintin Robinson

 9
Author: Albin Sunnanbo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:26:20

Title_Authors jest spojrzeniem na dwie rzeczy, które łączą się w wyniki projektu i kontynuują łańcuchowanie

        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;
        }
 9
Author: BionicCyborg,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-07-13 05:14:03

U można również użyć :

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 }
 8
Author: Baqer Naqvi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-10-21 14:09:01

Chciałbym podać inny przykład, w którym używa się wielu (3) złączeń.

 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
                  };
 3
Author: user3477428,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-10-07 03:08:15

Możesz również dołączyć, jeśli liczba kolumn nie jest taka sama w obu tabelach i możesz mapować wartość statyczną do kolumny tabeli

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}
 0
Author: Ankit Arya,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-11-02 08:00:20

Moim zdaniem jest to najprostszy sposób łączenia dwóch tabel z wieloma polami:

from a in Table1 join b in Table2    
       on (a.Field1.ToString() + "&" + a.Field2.ToString())     
       equals  (b.Field1.ToString() + "&" + b.Field2.ToString())  
     select a
 -4
Author: Praveen Kumar,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-09-21 08:37:09

Możesz napisać swoje zapytanie w ten sposób.

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

Jeśli chcesz porównać swoją kolumnę z wieloma kolumnami.

 -7
Author: Anvesh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-03-15 05:39:47