web-dev-qa-db-ja.com

JOIN拡張メソッドで左結合を実装する方法

p.Personテーブルのこの種のクエリに外部結合を実装しようとしています。どうすればいいですか?

この例は http://ashishware.com/DSLinqExample.shtml からの引用です

var onlyinfo = p.Person
    .Where(n => n.FirstName.Contains('a'))
    .Join(p.PersonInfo,
        n => n.PersonId,
        m => m.PersonId,
        (n, m) => m)
    .ToArray<Persons.PersonInfoRow>();
29
Shantanu Gupta

通常、LINQの左結合はグループ結合でモデル化され、場合によってはDefaultIfEmptyおよびSelectManyと組み合わせて使用​​されます。

var leftJoin = p.Person.Where(n => n.FirstName.Contains("a"))
                       .GroupJoin(p.PersonInfo, 
                                  n => n.PersonId,
                                  m => m.PersonId,
                                  (n, ms) => new { n, ms = ms.DefaultIfEmpty() })
                       .SelectMany(z => z.ms.Select(m => new { n = z.n, m }));

これにより、ペアのシーケンス(n、m)が得られます。ここで、np.Personからのエントリであり、mp.PersonInfoからのエントリですが、m一致がない場合はnullになります。

(それは完全にテストされていない、ところで-とにかくあなたにアイデアを与えるはずです:)

51
Jon Skeet

左外部結合の場合は、次のクエリを試してください。これはテストされています

var leftJoin = Table1
                .GroupJoin(
                               inner: Table2,
                    outerKeySelector: t1 => t1.Col1,
                    innerKeySelector: t2 => t2.Col2,
                      resultSelector: ( t1, t2Rows ) => new { t1, t2Rows.DefaultIfEmpty() }
                )
                .SelectMany( z =>
                    z.t2Rows.Select( t2 =>
                        new { t1 = z.t1, t2 = t2 }
                    )
                );
14
Harun Khan

誰かがこの質問に遭遇し、これを達成するための拡張メソッドが必要な場合は、他の回答と同じアプローチを使用して作成しました。通常の結合拡張メソッドと同じシグネチャを持っています。

    public static IEnumerable<TResult> LeftJoin<TOuter, TInner, TKey, TResult>(this IEnumerable<TOuter> outer,
        IEnumerable<TInner> inner, Func<TOuter, TKey> outerKeySelector, Func<TInner, TKey> innerKeySelector,
        Func<TOuter, TInner, TResult> resultSelector)
    {
        return outer
            .GroupJoin(inner, outerKeySelector, innerKeySelector, (outerObj, inners) =>
            new 
            {
                outerObj,
                inners= inners.DefaultIfEmpty()
            })
        .SelectMany(a => a.inners.Select(innerObj => resultSelector(a.outerObj, innerObj))); 
    }
8
bcwhims