LINQ to SQL:複数の列での複数の結合。これは可能ですか?


131

与えられた:

TABLE_1次の列で名前が付けられたテーブル:

  • ID
  • ColumnA
  • ColumnB
  • ColumnC

私は、SQLクエリ持ってTABLE_1二回のオフに基づいて、それ自体に参加するがColumnAColumnBColumnC。クエリは次のようになります。

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.

問題:

そのクエリをLINQで書き換える必要があります。私はそれを試してみました:

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

LINQでクエリを作成するにはどうすればよいですか?何が悪いのですか?

回答:


242

Linq to SQLの複数の列の結合は少し異なります。

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

匿名型を利用して、比較する複数の列の型を作成する必要があります。

これは最初は混乱しているように見えますが、SQLが式から構成される方法に慣れると、それは非常に理にかなっています。カバーの下で、これは探している結合のタイプを生成します。

編集コメントに基づく2番目の結合の例を追加します。

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
これは2つの結合に最適です。THREEジョインと連携するために必要です。2番目のコードブロックは少し誤解を招くものでした。
aarona

46
型推論に関するコンパイラエラーが発生した場合は、(1)型が同じか、(2)列名が同じか、2つのことを確認してください。名前の部分は落とし穴です。この例では、すべての列がvarcharsであってもコンパイルされませんjoin T2 in db.tbl2 on new { T1.firstName, T1.secondName } equals new { T2.colFirst, T2.colSecond }。これに変更すると、コンパイルは行われますが、join T2 in db.tbl2 on new { N1 = T1.firstName, N2 = T1.secondName } equals new { N1 = T2.colFirst, N2 = T2.colSecond }
user2023861

4
名前付けの問題は、myTABLE1Listのt1から、新しい{colA = t1.ColumnA、colB = t1.ColumnB}が新しい{colA = t2.ColumnA、colBBt2.ColumnB}に等しいmyTABLE1Listのt2から結合することで解消できます
Baqer Naqvi

1
匿名のプロパティへの割り当てが必要だったので、例を編集させてください
AceMark

1
何かがここで間違っています。複数のテーブルで結合したり、複数のフィールドで結合したりできますが、例に示すように、両方に対しては結合できません。したがって、1つのフィールドに結合があるだけで、それに続く2番目の結合があるとします。最初の結合(またはその両方)を変更して、new {x.field}がnew {y.field}と等しいだけを使用するようにすると、コンパイラエラーが発生します。機能的には何も変更していません。.Net 4.6.1の使用。
user2415376

12

LINQ2SQLでは、内部結合を使用するときに明示的に結合する必要はほとんどありません。

データベースに適切な外部キー関係がある場合、LINQデザイナーで自動的に関係が取得されます(データベースに適切な関係があるはずですが、デザイナーで手動で関係を作成できない場合)。

親子関係

次に、「ドット表記」を使用して関連するテーブルにアクセスできます

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

クエリを生成します

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

私の意見では、これはもっと読みやすく、結合の実際の仕組みではなく、特別な条件に集中することができます。

編集
これはもちろん、データベースモデルに参加したい場合にのみ適用されます。「モデルの外」に参加したい場合は、Quintin Robinsonからの回答のように手動で参加する必要があります


11

Title_Authorsは、プロジェクトの結果に同時に加わる2つの事柄を調べ、連鎖を続けます。

        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も使用できます:

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
ああ!これでうまくいきます!重要な違いは、「ColA =」の部分を実行して、他の結合で同じフィールドになるようにする必要があることです。何年もの間、私はそれをしませんでしたが、複数のフィールドで1つの結合が必要なだけでした。しかし、今はもっと必要で、この例のように変数名をフィールドに割り当てた場合にのみ機能します。
user2415376

3

複数の(3)結合が使用される別の例を示します。

 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
同じではありません-問題は、それぞれの単一の列に基づいて複数のテーブルを結合するのではなく、それぞれの複数の列に基づいてテーブルを結合することです。
アイソクロナス

1

列の数が両方のテーブルで同じでない場合も結合でき、静的な値をテーブルの列にマップできます

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

私の意見では、これは複数のフィールドを持つ2つのテーブルを結合する最も簡単な方法です。

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では、これを行うと、各列を個別に結合するよりも大幅に遅くなります(ただし、データセットが大きくない場合でも、かなり高速です)。おそらくlinqは明らかなSQLを生成するため、このソリューションを使用する場合はパフォーマンスを念頭に置いてください。
EGP

-10

このようにクエリを書くことができます。

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

列を複数の列と比較する場合。


1
@ user658720 StackOverFlowへようこそ:)。読みやすいようにコードをフォーマットすることをお勧めします。テキストを選択して、エディターのコードボタンをクリックできます。
aarona
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.