単一の結合で複数のフィールドをLINQで結合する方法


244

複数のフィールドで結合を行うLINQ2DataSetクエリを実行する必要があります(

var result = from x in entity
join y in entity2 
       on x.field1 = y.field1 
and 
          x.field2 = y.field2

私はまだ適切な解決策を見つけました(where句に追加の制約を追加できますが、これは適切な解決策とは程遠いか、この解決策を使用ますが、それは等価結合を前提としています)。

LINQでは、単一の結合で複数のフィールドに結合できますか?

編集

var result = from x in entity
             join y in entity2
             on new { x.field1, x.field2 } equals new { y.field1, y.field2 }

上記の等価結合を前提として参照したソリューションです。

さらに編集

私の最初の例が等結合であったという批判に答えるために、私はそれを認めます。私の現在の要件は等結合であり、上記で参照したソリューションをすでに採用しています。

ただし、私はLINQでどのような可能性とベストプラクティスを採用しているのかを理解しようとしています。すぐにテーブルIDで日付範囲クエリ結合を行う必要があり、その問題を先取りしていました。where句に日付範囲を追加する必要があるようです。

いつものように、与えられたすべての提案とコメントに感謝します


48
これを読んでいる人のための参考までに、annonクラスで複数フィールド結合を行う場合は、両方のannonクラスのフィールドに同じ名前を付ける必要があります。そうしないと、コンパイルエラーが発生します。
マーク

6
または、名前が一致していることを確認する必要があります。つまり、anonタイプの1つのフィールドに名前を付けて、他のフィールドと一致させることができます。
トムファーガソン

1
この回答に注意してください。stackoverflow.com/a/34176502/1704458
TS

オブジェクトではなくイコールのどちらかの側にタプルを使用しましたが、それも機能するようでした。
GHZ

回答:


89

匿名型のソリューションは正常に機能するはずです。LINQ (とにかく結合句を使用して)等結合のみを表すことができます。実際、これは、元のクエリに基づいてとにかく表現したいことです。

特定の理由で匿名タイプのバージョンが気に入らない場合は、その理由を説明する必要があります。

最初に求めた以外のことをしたい場合は、本当にやりたいことの例を挙げてください。

編集:質問の編集への応答:はい、「日付範囲」結合を行うには、代わりにwhere句を使用する必要があります。これらは実際には意味的に同等なので、利用できる最適化の問題です。等価結合は、内部シーケンスに基づいてルックアップを作成することにより(LINQ to Object、LINQ to DataSetsで)単純な最適化を提供します-キーからそのキーに一致するエントリのシーケンスへのハッシュテーブルと考えてください。

日付範囲でそれを行うのは少し難しいです。しかし、あなたは「日付が参加レンジ」の意味を正確にものに応じてあなたが何か行うことができるかもしれません同様のをあなたに発生している日付の「バンド」を作成する上での計画(年間例えば、1)その結果、2つのエントリ場合-同じ年(同じ日付ではない)が一致する必要がある場合、そのバンドをキーとして使用するだけで実行できます。それがより複雑である場合、たとえば、結合の片側が範囲を提供し、結合の反対側が単一の日付を提供し、その範囲内にある場合に一致する場合は、where(2番目の後にfrom節)IMO。より効率的に一致を見つけるために片側または反対側を注文することで、特にファンキーな魔法をかけることができますが、それは多くの作業になります-パフォーマンスが問題かどうかを確認した後でのみ、そのようなことを行います。


おかげで、パフォーマンスはwhere句の使用に関する私の主な心配事です。結合後のwhere句は、2番目の結合パラメーターを導入することで削減できたより大きなデータセットに対してフィルターを実行すると思います。私は、効率性の向上を得ることができれば私がテストを発注のアイデアのように行う
JOHNC

いくつの記録がありますか?結果の開始を開始するには、ある程度の時間がかかることを忘れないでください...
Jon Skeet

「それらは本当に意味的に同等です」-そこに「本当に」という言葉が必要ですか?おそらく、あなたは「彼らがしている、意味本当に :)意味的に等価」
onedaywhen

136
var result = from x in entity
   join y in entity2 on new { x.field1, x.field2 } equals new { y.field1, y.field2 }

これは、101 Linqサンプルにこれがない、または少なくとも私が見たものがないので、私が探していたものです。
Chris Marisic 2013

1
@PeterX確かにそれは、ここに私の答えを見ることができます:stackoverflow.com/a/22176658/595157
niieani

13
上記のコードは機能しませんでした。追加後、動作しon new { X1= x.field1, X2= x.field2 } equals new { X1=y.field1, X2= y.field2 } ました
Ravi Ram、

@Ravi Ram ..ありがとう..あなたのコメントが
役に立ち

80
var result = from x in entity1
             join y in entity2
             on new { X1= x.field1, X2= x.field2 } equals new { X1=y.field1, X2= y.field2 }

列名が2つのエンティティで異なる場合は、これを行う必要があります。


6
さまざまな列名について言及していただきありがとうございます。これは私の悪い表現を修正しました。
Gaʀʀʏ

1
これも私にとってはうまくいきました。列名が一致しない場合、「結合句の式の1つのタイプが正しくありません。「GroupJoin」の呼び出しで型の推論に失敗しました。」というエラーが発生します。
humbads

キー変数にエイリアスを設定していただきありがとうございます。
Thomas.Benz 2017年

intのすべてのプロパティに「新しい{}」という名前を付けなかったときに@humbadsが言及したエラーが発生しました。だから、もしあなたが名前を付ければ、残りも名前を付けなければならない。
Ethan Melamed、

ありがとうございました
チャーリーH

51

同等のメソッドチェーン構文でこれを完了するだけです。

entity.Join(entity2, x => new {x.Field1, x.Field2},
                     y => new {y.Field1, y.Field2}, (x, y) => x);

最後の引数(x, y) => xはユーザーが選択するものです(上記の場合はを選択しますx)。


31

より読みやすく柔軟なオプションはWhere関数を使用することだと思います。

var result = from x in entity1
             from y in entity2
                 .Where(y => y.field1 == x.field1 && y.field2 == x.field2)

これにより、.DefaultIfEmpty()を追加することで、内部結合から左結合に簡単に変更できます。


長いラムダユーザーとして(私が質問したときとは対照的に)、私は同意する必要があります
johnc

これは遅いでしょうか?
AlfredBr 2016

1
新しい{ ... } equals new { ... }構文と同じパフォーマンスになるはずです。LinqPadは、式の動作を確認するための優れたツールです(LINQ2SQLが使用されている場合のSQLスクリプト、式ツリーなど)
Alexei

私が気付いた限りでは、INNER JOINではなくCROSS JOINを生成しています
Mariusz

@Mariuszはい、INNER JOINの代わりにCROSS JOIN + WHEREを生成することは理にかなっています。単純なクエリの場合は、アナライザーが非常によく似たものを生成することを期待しています。
アレクセイ

10
var result = from x in entity
             join y in entity2
             on new { X1= x.field1, X2= x.field2 } equals new { X1=y.field1, X2= y.field2 }
             select new 
             {
               /// Columns
              };

8

あなたは(以下)のようなことをすることができます

var query = from p in context.T1

        join q in context.T2

        on

        new { p.Col1, p.Col2 }

        equals

         new { q.Col1, q.Col2 }

        select new {p...., q......};

質問で述べたように、これには等価結合が必要です
johnc 2008

7

結合演算子を使用すると、等結合のみを実行できます。他のタイプの結合は、他の演算子を使用して構築できます。あなたがしようとしている正確な結合がこれらのメソッドを使用するか、where句を変更することで簡単になるかどうかはわかりません。結合句に関するドキュメントはここにあります。MSDNには、他の結合の例への複数のリンクがある結合操作に関する記事もあります。


3

エンティティでフィールド名が異なる場合

var result = from x in entity
   join y in entity2 on 
          new {
                field1=   x.field1,
               field2 =  x.field2 
             } 
          equals
         new { 
                field1= y.field1,
                field2=  y.myfield
              }
select new {x,y});

ありがとうございました。名前の一致は、私が欠けていた部分でした。
ブレット

2

次のような完全なメソッドチェーンとして:

lista.SelectMany(a => listb.Where(xi => b.Id == a.Id && b.Total != a.Total),
                (a, b) => new ResultItem
                {
                    Id = a.Id,
                    ATotal = a.Total,
                    BTotal = b.Total
                }).ToList();

-2
from d in db.CourseDispatches
                             join du in db.DispatchUsers on d.id equals du.dispatch_id
                             join u in db.Users on du.user_id equals u.id
                             join fr in db.Forumreports on (d.course_id + '_' + du.user_id)  equals  (fr.course_id + '_'+ fr.uid)

これは私のために働く


これは複数の結合用であり、1つの結合で複数のフィールドを使用した結合を作成したいと考えています
theLaw

-3

結合する要素を保持するClass(Type)を宣言します。以下の例では、JoinElementを宣言しています

 public class **JoinElement**
{
    public int? Id { get; set; }
    public string Name { get; set; }

}

results = from course in courseQueryable.AsQueryable()
                  join agency in agencyQueryable.AsQueryable()
                   on new **JoinElement**() { Id = course.CourseAgencyId, Name = course.CourseDeveloper } 
                   equals new **JoinElement**() { Id = agency.CourseAgencyId, Name = "D" } into temp1

1
これは9年前にすでに回答されています...この回答はどのような価値をもたらしますか?
Maciej Jureczko
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.