Linqからエンティティへの結合とグループ結合


182

ウェブで検索しましたが、それでも簡単な答えは見つかりません。誰かが(簡単な英語で)何を説明できますかGroupJoin?通常のインナーとどう違うのJoin?一般的に使用されていますか?それはメソッド構文専用ですか?クエリ構文はどうですか?C#のコード例がいいでしょう。


MSDNによると、グループ結合はinto式を使用した結合句です。 結合句には、より多くの情報とコードサンプルがあります。これは本質的に内部結合です(右側の要素が左側の要素と一致しない場合、結果はnullになります)。ただし、結果はグループに編成されます。
Tim

回答:


375

動作

次の2つのリストがあるとします。

Id  Value
1   A
2   B
3   C

Id  ChildValue
1   a1
1   a2
1   a3
2   b1
2   b2

フィールドにJoin2つのリストがある場合Id、結果は次のようになります。

Value ChildValue
A     a1
A     a2
A     a3
B     b1
B     b2

フィールドにGroupJoin2つのリストがある場合Id、結果は次のようになります。

Value  ChildValues
A      [a1, a2, a3]
B      [b1, b2]
C      []

したがってJoin、親と子の値のフラットな(表形式の)結果が生成されます。
GroupJoin最初のリストのエントリのリストを作成します。各リストには、2番目のリストの結合されたエントリのグループがあります。

なぜだというJoinのと等価であるINNER JOINSQLでは:のためのエントリがありませんC。while GroupJoinOUTER JOINCと同等ですが、結果セットには含まれますが、関連するエントリの空のリストが含まれます(SQL結果セットには行がありますC - null)。

構文

したがって、2つのリストIEnumerable<Parent>IEnumerable<Child>それぞれとします。(Linq to Entitiesの場合:)IQueryable<T>

Join 構文は

from p in Parent
join c in Child on p.Id equals c.Id
select new { p.Value, c.ChildValue }

帰国IEnumerable<X>ここで、Xは、2つのプロパティを持つ匿名型である、ValueChildValue。このクエリ構文では、Join内部でメソッドを使用します。

GroupJoin 構文は

from p in Parent
join c in Child on p.Id equals c.Id into g
select new { Parent = p, Children = g }

AN復帰IEnumerable<Y>Yタイプのプロパティからなる匿名型であるParentとタイプのプロパティをIEnumerable<Child>。このクエリ構文では、GroupJoin内部でメソッドを使用します。

select g後者のクエリIEnumerable<IEnumerable<Child>>では、リストのリストなどのを選択するだけで実行できます。多くの場合、親を含む選択がより便利です。

いくつかのユースケース

1.フラットな外部結合を作成します。

言ったように、ステートメント...

from p in Parent
join c in Child on p.Id equals c.Id into g
select new { Parent = p, Children = g }

...子グループを持つ親のリストを生成します。これは、2つの小さな追加により、親子ペアのフラットリストに変換できます。

from p in parents
join c in children on p.Id equals c.Id into g // <= into
from c in g.DefaultIfEmpty()               // <= flattens the groups
select new { Parent = p.Value, Child = c?.ChildValue }

結果は次のようになります

Value Child
A     a1
A     a2
A     a3
B     b1
B     b2
C     (null)

上記のステートメントでは、範囲変数 cが再利用されていることに注意してください。これを行うと、既存のステートメントに同等のものを追加joinするだけで、任意のステートメントを単純にに変換できます。outer joininto g from c in g.DefaultIfEmpty()join

これは、クエリ(または包括的な)構文が優れている点です。メソッド(または流暢)構文は実際に何が起こるかを示しますが、書くのは難しいです:

parents.GroupJoin(children, p => p.Id, c => c.Id, (p, c) => new { p, c })
       .SelectMany(x => x.c.DefaultIfEmpty(), (x,c) => new { x.p.Value, c?.ChildValue } )

したがって、outer joinLINQのフラットはGroupJoinによってフラット化されSelectManyます。

2.順序を維持する

親のリストが少し長いと仮定します。一部のUIでは、選択された親のリストがId値として固定された順序で生成されます。使ってみましょう:

var ids = new[] { 3,7,2,4 };

次に、選択した親をこの正確な順序で親リストからフィルタリングする必要があります。

私たちがするなら...

var result = parents.Where(p => ids.Contains(p.Id));

...の順序parentsによって結果が決まります。親がで並べられているId場合、結果は親2、3、4、7になります。ただし、joinリストのフィルタリングにも使用できます。そして、ids最初のリストとして使用することにより、順序は保持されます:

from id in ids
join p in parents on id equals p.Id
select p

結果は親3、7、2、4です。


GroupJoinでは、子の値にオブジェクトが含まれ、関連する値が含まれていますか?
duyn9uyen 2013年

GroupJoinは外部結合のようなものですが、その構文(グループ結合の純粋なlinq)は、外部結合のようなものではなく、左外部結合を示しています。
Imad

2
「フラット外部結合」が左外部結合であることを指定すると思います。
NetMage 2017

1
完全に説明された、私は今理解している
-peterincumbria

19

eduLINQによると:

GroupJoinの機能を理解するための最良の方法は、Joinについて考えることです。そこで、全体的なアイデアは、「外部」入力シーケンスを調べ、「内部」シーケンスから一致するすべてのアイテムを見つけ(各シーケンスのキープロジェクションに基づく)、一致する要素のペアを生成するというものでした。GroupJoinは似ていますが、要素のペアを生成するのではなく、そのアイテムと一致する「内部」アイテムのシーケンスに基づいて、「外部」アイテムごとに1つの結果を生成します

唯一の違いはreturnステートメントです。

参加

var lookup = inner.ToLookup(innerKeySelector, comparer); 
foreach (var outerElement in outer) 
{ 
    var key = outerKeySelector(outerElement); 
    foreach (var innerElement in lookup[key]) 
    { 
        yield return resultSelector(outerElement, innerElement); 
    } 
} 

GroupJoin

var lookup = inner.ToLookup(innerKeySelector, comparer); 
foreach (var outerElement in outer) 
{ 
    var key = outerKeySelector(outerElement); 
    yield return resultSelector(outerElement, lookup[key]); 
} 

詳細はこちら:

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.