LINQ to SQL: Birden çok Sütunda birden çok birleşim. Mümkün mü?


131

Verilen:

TABLE_1Aşağıdaki sütunlarla adlandırılmış bir tablo :

  • ID
  • ColumnA
  • ColumnB
  • ColumnC

Nerede SQL sorgusu sahip TABLE_1iki kez kapalı tabanlı kendi üzerine katılır ColumnA, ColumnB, ColumnC. Sorgu şunun gibi görünebilir:

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.

Sorun:

Bu Sorgunun LINQ'da yeniden yazılmasına ihtiyacım var. Bıçaklamayı denedim:

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

Sorgumu LINQ'da nasıl yazarım? Neyi yanlış yapıyorum?

Yanıtlar:


243

Linq to SQL'de birden çok sütuna katılmak biraz farklıdır.

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

Anonim türlerden yararlanmalı ve karşılaştırmak istediğiniz birden çok sütun için bir tür oluşturmalısınız.

Bu ilk bakışta kafa karıştırıcı gibi görünebilir ancak SQL'in ifadelerden nasıl oluşturulduğunu öğrendiğinizde çok daha anlamlı olacaktır, kapakların altında bu aradığınız birleştirme türünü üretecektir.

DÜZENLE Yoruma göre ikinci birleştirme için örnek ekleniyor .

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

4
bu iki birleştirme için harika çalışıyor. ÜÇ katılımla çalışması için ona ihtiyacım var. Üzgünüm, ikinci kod bloğu biraz yanıltıcıydı.
aarona

46
Tür çıkarımıyla ilgili bir derleyici hatası alırsanız, iki şeyi kontrol edin, (1) türler aynıdır ve (2) sütun adları aynıdır. İsimler kısmı bir aldatmaca. Bu örnek, tüm sütunlar varchars olsa bile derlenmeyecektir join T2 in db.tbl2 on new { T1.firstName, T1.secondName } equals new { T2.colFirst, T2.colSecond }. Bunu buna değiştirirseniz, derlenecektirjoin T2 in db.tbl2 on new { N1 = T1.firstName, N2 = T1.secondName } equals new { N1 = T2.colFirst, N2 = T2.colSecond }
user2023861

4
Adlandırma sorunu, yeni {colA = t1.ColumnA, colB = t1.ColumnB} eşittir yeni {colA = t2.ColumnA, colBBt2.ColumnB}
Naqvi

1
lütfen anonim mülklere atamalara ihtiyaç duyduğu için örneği düzenlememe izin verin
AceMark

1
Burada bir sorun var .. LINQ ile. Birden fazla masaya katılabilirim, birden fazla alana katılabilirim ... ancak burada örnekte gösterildiği gibi her ikisi için de yapamam. Diyelim ki 1 alanda bir katılımınız var .. ve onu izleyen 2. bir katılımınız var. İlk birleştirmeyi (veya her ikisini) yalnızca yeni {x.field} eşittir yeni {y.field} kullanmak için değiştirirseniz bir derleyici hatası oluşur. İşlevsel olarak hiçbir şeyi değiştirmedin. .Net Kullanımı 4.6.1.
user2415376

12

LINQ2SQL'de, iç birleştirmeleri kullanırken nadiren açıkça katılmanız gerekir.

Veritabanınızda uygun yabancı anahtar ilişkileriniz varsa, LINQ tasarımcısında otomatik olarak bir ilişki elde edersiniz (yoksa tasarımcıda manuel olarak bir ilişki oluşturabilirsiniz, ancak veritabanınızda gerçekten uygun ilişkilere sahip olmanız gerekir)

ebeveyn-çocuk ilişkisi

Daha sonra "noktalı gösterim" ile ilgili tablolara erişebilirsiniz.

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

sorgu oluşturacak

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

Bence bu çok daha okunabilir ve birleştirmenin gerçek mekaniğine değil, özel koşullarınıza odaklanmanıza izin veriyor.

Düzenle
Bu, elbette yalnızca veritabanı modelimiz doğrultusunda katılmak istediğinizde geçerlidir. "Modelin dışında" katılmak istiyorsanız , Quintin Robinson'ın yanıtında olduğu gibi manuel birleştirmelere başvurmanız gerekir.


11

Title_Authors, bir seferde proje sonuçlarının birleştirilmesi ve zincirlemeye devam edilmesi

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

10

U şunları da kullanabilirsiniz:

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 }

3
Ahhh !! Bu çalışıyor! Ve ANAHTAR FARK, "ColA =" bölümünü yapmanız gerektiğidir, böylece diğer birleşimde aynı alan olur. Yıllarca bunu yapmadım, ancak aynı zamanda birden fazla alanda 1 katılıma ihtiyacım olacaktı. Ama şimdi daha fazlasına ihtiyacım var ve YALNIZCA bu örnekteki gibi alanlara bir değişken adı atarsam ÇALIŞIR.
user2415376

3

Çoklu (3) birleşimlerin kullanıldığı başka bir örnek vermek istiyorum.

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

9
Aynı şey değil - soru, her birinde tek bir sütuna dayalı birden çok tabloyu birleştirmekle değil, her birinde birden çok sütuna dayalı tabloları birleştirmekle ilgilidir.
Eşzamanlı

1

Her iki tabloda da sütun sayısı aynı değilse de birleştirebilir ve statik değeri tablo sütununa eşleyebilirsiniz.

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}

-6

Kanımca, iki tabloyu birden çok alanla birleştirmenin en basit yolu budur:

from a in Table1 join b in Table2    
       on (a.Field1.ToString() + "&" + a.Field2.ToString())     
       equals  (b.Field1.ToString() + "&" + b.Field2.ToString())  
     select a

SQL'de, bunu yapmak her bir sütuna ayrı ayrı katılmaktan önemli ölçüde daha yavaş olurdu (yine de veri kümesi büyük değilse yine de oldukça hızlı olurdu). Muhtemelen linq bariz SQL oluşturacaktır, bu nedenle bu çözümü kullanıyorsanız performansı aklınızda bulundurun.
EGP

-10

Sorgunuzu bu şekilde yazabilirsiniz.

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

Sütununuzu birden çok sütunla karşılaştırmak istiyorsanız.


1
@ user658720 StackOverFlow'a hoş geldiniz :). Kodunuzu daha kolay okunacak şekilde biçimlendirmenizi öneririm. Metni seçebilir ve düzenleyicideki kod düğmesini tıklayabilirsiniz.
aarona
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.