'How to implement left join in JOIN Extension method
I am trying to implement an outer join on this kind of query for the p.Person
table.
How would I do this?
This example is taken from 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>();
Solution 1:[1]
Normally left joins in LINQ are modelled with group joins, sometimes in conjunction with DefaultIfEmpty
and 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 }));
That will give a sequence of pairs (n, m) where n
is the entry from p.Person
and m
is the entry from p.PersonInfo
, but m
will be null if there are no matches.
(It's completely untested, btw - but should give you the idea anyway :)
Solution 2:[2]
For Left outer Join try Following query. This is tested
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 }
)
);
Solution 3:[3]
If anyone comes across this question and wants an extension method to accomplish this, I created one using the same approach as the other answers. It has the same signature as the regular join extension method.
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)));
}
Solution 4:[4]
I have used the following extension method on of my project, It might help you.
/// <summary>
/// Performs a left outer join on two collections.
/// </summary>
/// <typeparam name="TLeft">Type of left IEnumerable collection</typeparam>
/// <typeparam name="TRight">Type of left IEnumerable collection</typeparam>
/// <typeparam name="TKey">The type of the key returned by the key selector functions.</typeparam>
/// <typeparam name="TResult">The type of the result elements.</typeparam>
/// <param name="left"> The left IEnumerable collection of the join operation.</param>
/// <param name="right"> The right IEnumerable collection of the join operation.</param>
/// <param name="leftKeySelector">Function that projects the key given an element from <paramref name="left"/>.</param>
/// <param name="rightKeySelector">Function that projects the key given an element from <paramref name="right"/>.</param>
/// <param name="resultSelector">Function that projects the result given
/// an element from <paramref name="left"/> and
/// an element from <paramref name="right"/>
/// that match on a common key.</param>
/// <returns>A sequence containing results projected from a left outer join of the two input collections.</returns>
public static IQueryable<TResult> LeftJoin<TLeft, TRight, TKey, TResult>(
this IQueryable<TLeft> left,
IQueryable<TRight> right,
Expression<Func<TLeft, TKey>> leftKeySelector,
Expression<Func<TRight, TKey>> rightKeySelector,
Expression<Func<TLeft, TRight, TResult>> resultSelector)
{
if (left == null) throw new ArgumentNullException(nameof(left));
if (right == null) throw new ArgumentNullException(nameof(right));
if (leftKeySelector == null) throw new ArgumentNullException(nameof(leftKeySelector));
if (rightKeySelector == null) throw new ArgumentNullException(nameof(rightKeySelector));
if (resultSelector == null) throw new ArgumentNullException(nameof(resultSelector));
return left
.AsExpandable() // LinqKit to convert everything into an expression tree.
.GroupJoin(
right,
leftKeySelector,
rightKeySelector,
(leftItem, rightItem) => new { leftItem, rightItem })
.SelectMany(
joinResult => joinResult.rightItem.DefaultIfEmpty(),
(joinResult, rightItem) =>
resultSelector.Invoke(joinResult.leftItem, rightItem));
}
And this is how it was called
base.context.Users
.LeftJoin(
base.context.Workers
user => user.Userid,
worker => worker.Workerid,
(user, worker) => new
{
User = user,
Worker = worker
})
Got this answer here, Trying to implement a LeftJoin extension method to work with EF Core 2.0
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | Michał Turczyn |
Solution 2 | Dai |
Solution 3 | Vadim Ovchinnikov |
Solution 4 |