LINQ ke SQL: Beberapa bergabung PADA beberapa Kolom. Apakah ini mungkin?

131

Diberikan:

Tabel yang diberi nama TABLE_1dengan kolom berikut:

  • ID
  • ColumnA
  • ColumnB
  • ColumnC

Saya memiliki query SQL di mana TABLE_1bergabung pada dirinya sendiri dua kali didasarkan dari ColumnA, ColumnB, ColumnC. Kueri mungkin terlihat seperti ini:

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.

Masalah:

Saya membutuhkan Query untuk ditulis ulang di LINQ. Saya sudah mencoba menikamnya:

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

Bagaimana saya menulis permintaan saya di LINQ? Apa yang saya lakukan salah?

aarona
sumber

Jawaban:

242

Bergabung pada banyak kolom dalam Linq ke SQL sedikit berbeda.

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

Anda harus memanfaatkan jenis anonim dan menulis jenis untuk beberapa kolom yang ingin Anda bandingkan.

Ini tampaknya membingungkan pada awalnya tetapi begitu Anda berkenalan dengan cara SQL disusun dari ekspresi itu akan lebih masuk akal, di bawah selimut ini akan menghasilkan jenis gabungan yang Anda cari.

EDIT Menambahkan contoh untuk gabung kedua berdasarkan komentar.

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
sumber
4
ini bekerja sangat baik untuk dua bergabung. Saya membutuhkannya untuk bekerja dengan TIGA bergabung. Maaf, blok kode kedua agak menyesatkan.
aarona
46
Jika Anda mendapatkan kesalahan kompilator tentang inferensi jenis, periksa dua hal, (1) adalah jenis yang sama, dan (2) adalah nama kolom yang sama. Bagian nama adalah gotcha. Contoh ini tidak akan dikompilasi bahkan jika semua kolom adalah varchars join T2 in db.tbl2 on new { T1.firstName, T1.secondName } equals new { T2.colFirst, T2.colSecond }. Jika Anda mengubahnya ke ini, itu akan dikompilasi,join T2 in db.tbl2 on new { N1 = T1.firstName, N2 = T1.secondName } equals new { N1 = T2.colFirst, N2 = T2.colSecond }
user2023861
4
Masalah penamaan dapat dihilangkan dengan dari t1 di myTABLE1List, bergabung dengan t2 di myTABLE1List pada {colA = t1.ColumnA, colB = t1.ColumnB} baru sama dengan {colA = t2.ColumnA, colBBt2.ColumnB}
Baqer Naqvi
1
tolong izinkan saya untuk mengedit contoh, karena diperlukan tugas untuk properti anonim
AceMark
1
Ada yang salah di sini .. dengan LINQ. Saya dapat bergabung di beberapa tabel, saya dapat bergabung di beberapa bidang ... namun, saya tidak dapat melakukannya untuk keduanya, seperti contoh di sini. Jadi, katakan saja Anda hanya bergabung di 1 bidang .. dan Anda memiliki 2 bergabung mengikutinya. Jika Anda mengubah 1 bergabung (atau keduanya) untuk hanya menggunakan {x.field} baru sama dengan baru {y.field} ada kesalahan kompiler. Secara fungsional Anda tidak mengubah apa pun. Menggunakan .Net 4.6.1.
user2415376
12

Di LINQ2SQL Anda jarang perlu bergabung secara eksplisit saat menggunakan inner joins.

Jika Anda memiliki hubungan kunci asing yang tepat dalam database Anda, Anda akan secara otomatis mendapatkan relasi di perancang LINQ (jika tidak, Anda dapat membuat relasi secara manual di perancang, meskipun Anda harus benar-benar memiliki hubungan yang tepat dalam database Anda)

hubungan orangtua-anak

Kemudian Anda bisa mengakses tabel terkait dengan "titik-notasi"

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

akan menghasilkan kueri

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

Menurut pendapat saya ini jauh lebih mudah dibaca dan memungkinkan Anda berkonsentrasi pada kondisi khusus Anda dan bukan mekanisme yang sebenarnya bergabung.

Sunting
Ini tentu saja hanya berlaku ketika Anda ingin bergabung dengan model database kami. Jika Anda ingin bergabung dengan "di luar model" Anda harus menggunakan gabungan manual seperti pada jawaban dari Quintin Robinson

Albin Sunnanbo
sumber
11

Title_Authors adalah melihat dua hal bergabung pada hasil proyek waktu dan terus chaining

        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
sumber
10

Anda juga dapat menggunakan:

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
sumber
3
AHHH !! Ini bekerja! Dan PERBEDAAN KUNCI, adalah bahwa Anda perlu melakukan bagian "ColA =" sehingga yang lain bergabung dengan bidang yang sama. Selama bertahun-tahun saya tidak melakukan itu, tetapi juga hanya perlu 1 bergabung di beberapa bidang. Tetapi sekarang saya membutuhkan lebih banyak, dan itu HANYA BEKERJA jika saya memberikan nama variabel ke bidang seperti dalam contoh ini.
user2415376
3

Saya ingin memberikan contoh lain di mana banyak (3) gabungan digunakan.

 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
                  };
pengguna3477428
sumber
9
Bukan hal yang sama - pertanyaannya adalah tentang menggabungkan tabel berdasarkan beberapa kolom di masing-masing, tidak bergabung dengan beberapa tabel berdasarkan satu kolom di masing-masing.
Isochronous
1

Anda juga dapat bergabung jika jumlah kolom tidak sama di kedua tabel dan dapat memetakan nilai statis ke kolom tabel

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
sumber
-6

Menurut pendapat saya, ini adalah cara paling sederhana untuk bergabung dengan dua tabel dengan beberapa bidang:

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
sumber
Dalam SQL, melakukan ini akan jauh lebih lambat daripada bergabung pada setiap kolom secara terpisah (meskipun masih akan cukup cepat jika dataset tidak besar). Mungkin linq akan menghasilkan SQL yang jelas, jadi ingatlah selalu kinerja jika Anda menggunakan solusi ini.
EGP
-10

Anda dapat menulis kueri Anda seperti ini.

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

Jika Anda ingin membandingkan kolom Anda dengan beberapa kolom.

Landasan
sumber
1
@ user658720 Selamat datang di StackOverFlow :). Saya menyarankan agar Anda memformat kode Anda sehingga lebih mudah dibaca. Anda dapat memilih teks dan mengklik tombol kode pada editor.
aarona