score:519
For a (left outer) join of a table Bar
with a table Foo
on Foo.Foo_Id = Bar.Foo_Id
in lambda notation:
var qry = Foo.GroupJoin(
Bar,
foo => foo.Foo_Id,
bar => bar.Foo_Id,
(x,y) => new { Foo = x, Bars = y })
.SelectMany(
x => x.Bars.DefaultIfEmpty(),
(x,y) => new { Foo=x.Foo, Bar=y});
score:0
Marc Gravell's answer turn into an extension method that support the IQueryable<T>
interface is given in this answer and with added support for C# 8.0 NRT reads as follows:
#nullable enable
using LinqKit;
using LinqKit.Core;
using System.Linq.Expressions;
...
/// <summary>
/// Left join queryable. Linq to SQL compatible. IMPORTANT: any Includes must be put on the source collections before calling this method.
/// </summary>
public static IQueryable<TResult> LeftJoin<TOuter, TInner, TKey, TResult>(
this IQueryable<TOuter> outer,
IQueryable<TInner> inner,
Expression<Func<TOuter, TKey>> outerKeySelector,
Expression<Func<TInner, TKey>> innerKeySelector,
Expression<Func<TOuter, TInner?, TResult>> resultSelector)
{
return outer
.AsExpandable()
.GroupJoin(
inner,
outerKeySelector,
innerKeySelector,
(outerItem, innerItems) => new { outerItem, innerItems })
.SelectMany(
joinResult => joinResult.innerItems.DefaultIfEmpty(),
(joinResult, innerItem) =>
resultSelector.Invoke(joinResult.outerItem, innerItem));
}
score:2
Turning Marc Gravell's answer into an extension method, I made the following.
internal static IEnumerable<Tuple<TLeft, TRight>> LeftJoin<TLeft, TRight, TKey>(
this IEnumerable<TLeft> left,
IEnumerable<TRight> right,
Func<TLeft, TKey> selectKeyLeft,
Func<TRight, TKey> selectKeyRight,
TRight defaultRight = default(TRight),
IEqualityComparer<TKey> cmp = null)
{
return left.GroupJoin(
right,
selectKeyLeft,
selectKeyRight,
(x, y) => new Tuple<TLeft, IEnumerable<TRight>>(x, y),
cmp ?? EqualityComparer<TKey>.Default)
.SelectMany(
x => x.Item2.DefaultIfEmpty(defaultRight),
(x, y) => new Tuple<TLeft, TRight>(x.Item1, y));
}
score:3
Whilst the accepted answer works and is good for Linq to Objects it bugged me that the SQL query isn't just a straight Left Outer Join.
The following code relies on the LinqKit Project that allows you to pass expressions and invoke them to your query.
static IQueryable<TResult> LeftOuterJoin<TSource,TInner, TKey, TResult>(
this IQueryable<TSource> source,
IQueryable<TInner> inner,
Expression<Func<TSource,TKey>> sourceKey,
Expression<Func<TInner,TKey>> innerKey,
Expression<Func<TSource, TInner, TResult>> result
) {
return from a in source.AsExpandable()
join b in inner on sourceKey.Invoke(a) equals innerKey.Invoke(b) into c
from d in c.DefaultIfEmpty()
select result.Invoke(a,d);
}
It can be used as follows
Table1.LeftOuterJoin(Table2, x => x.Key1, x => x.Key2, (x,y) => new { x,y});
score:7
Improving on Ocelot20's answer, if you have a table you're left outer joining with where you just want 0 or 1 rows out of it, but it could have multiple, you need to Order your joined table:
var qry = Foos.GroupJoin(
Bars.OrderByDescending(b => b.Id),
foo => foo.Foo_Id,
bar => bar.Foo_Id,
(f, bs) => new { Foo = f, Bar = bs.FirstOrDefault() });
Otherwise which row you get in the join is going to be random (or more specifically, whichever the db happens to find first).
score:19
You can create extension method like:
public static IEnumerable<TResult> LeftOuterJoin<TSource, TInner, TKey, TResult>(this IEnumerable<TSource> source, IEnumerable<TInner> other, Func<TSource, TKey> func, Func<TInner, TKey> innerkey, Func<TSource, TInner, TResult> res)
{
return from f in source
join b in other on func.Invoke(f) equals innerkey.Invoke(b) into g
from result in g.DefaultIfEmpty()
select res.Invoke(f, result);
}
score:65
Group Join method is unnecessary to achieve joining of two data sets.
Inner Join:
var qry = Foos.SelectMany
(
foo => Bars.Where (bar => foo.Foo_id == bar.Foo_id),
(foo, bar) => new
{
Foo = foo,
Bar = bar
}
);
For Left Join just add DefaultIfEmpty()
var qry = Foos.SelectMany
(
foo => Bars.Where (bar => foo.Foo_id == bar.Foo_id).DefaultIfEmpty(),
(foo, bar) => new
{
Foo = foo,
Bar = bar
}
);
EF and LINQ to SQL correctly transform to SQL. For LINQ to Objects it is beter to join using GroupJoin as it internally uses Lookup. But if you are querying DB then skipping of GroupJoin is AFAIK as performant.
Personlay for me this way is more readable compared to GroupJoin().SelectMany()
score:143
Since this seems to be the de facto SO question for left outer joins using the method (extension) syntax, I thought I would add an alternative to the currently selected answer that (in my experience at least) has been more commonly what I'm after
// Option 1: Expecting either 0 or 1 matches from the "Right"
// table (Bars in this case):
var qry = Foos.GroupJoin(
Bars,
foo => foo.Foo_Id,
bar => bar.Foo_Id,
(f,bs) => new { Foo = f, Bar = bs.SingleOrDefault() });
// Option 2: Expecting either 0 or more matches from the "Right" table
// (courtesy of currently selected answer):
var qry = Foos.GroupJoin(
Bars,
foo => foo.Foo_Id,
bar => bar.Foo_Id,
(f,bs) => new { Foo = f, Bars = bs })
.SelectMany(
fooBars => fooBars.Bars.DefaultIfEmpty(),
(x,y) => new { Foo = x.Foo, Bar = y });
To display the difference using a simple data set (assuming we're joining on the values themselves):
List<int> tableA = new List<int> { 1, 2, 3 };
List<int?> tableB = new List<int?> { 3, 4, 5 };
// Result using both Option 1 and 2. Option 1 would be a better choice
// if we didn't expect multiple matches in tableB.
{ A = 1, B = null }
{ A = 2, B = null }
{ A = 3, B = 3 }
List<int> tableA = new List<int> { 1, 2, 3 };
List<int?> tableB = new List<int?> { 3, 3, 4 };
// Result using Option 1 would be that an exception gets thrown on
// SingleOrDefault(), but if we use FirstOrDefault() instead to illustrate:
{ A = 1, B = null }
{ A = 2, B = null }
{ A = 3, B = 3 } // Misleading, we had multiple matches.
// Which 3 should get selected (not arbitrarily the first)?.
// Result using Option 2:
{ A = 1, B = null }
{ A = 2, B = null }
{ A = 3, B = 3 }
{ A = 3, B = 3 }
Option 2 is true to the typical left outer join definition, but as I mentioned earlier is often unnecessarily complex depending on the data set.
Source: stackoverflow.com
Related Query
- How do you perform a left outer join using linq extension methods
- How do you perform a left outer join with a where clause using linq lambda extension methods
- How to perform LINQ left outer join using method syntax?
- Extension method for IQueryable left outer join using LINQ
- Left outer join using LINQ -- understanding the code
- How can I implement a LEFT OUTER JOIN in LINQ using lambda syntax on Entity Framework Core 2.0?
- How can I code an outer join using LINQ and EF6?
- How to perform left outer join in Linq
- Need Left Outer Join in LINQ using Extension Method /Query Syntax
- How to convert a SQL with multiple left joins to an Entity Framework LINQ statement using Include methods (No Join methods)?
- Using LINQ to perform a left outer join
- Left Outer Join SQL to LINQ Extension Methods
- LINQ Left Outer join with group by count through extension methods
- How to perform left join using two or more table in LInq to Sql query?
- Left outer join to perform DataTable Comparison using Linq
- How do you perform a CROSS JOIN with LINQ to SQL?
- How to limit a LINQ left outer join to one row
- Nice, clean cross join in Linq using only extension methods
- How do you left join in Linq if there is more than one field in the join?
- How to do a left outer join in Entity Framework without using the query syntax?
- LINQ: How to do JOIN using the linq extension method style on multiple fields?
- How to write a LEFT OUTER JOIN where the right side is null in LINQ to SQL?
- How to perform Dynamic Join using LINQ
- Left outer join null using VB.NET and LINQ
- Linq left outer join not working using DefaultIfEmpty
- How do C# Linq extension methods perform equality comparison?
- How to add left outer join to grouped and summed LINQ query
- LINQ; How to perform left outer join with multiple conditions?
- Left outer join using LINQ Query Syntax EF Core C#
- Entity Framework: How to perform left join with EF and LINQ among multiple tables
More Query from same tag
- Unable to deserialize JSON array
- Removing redunancies between LINQ queries
- Using ToString to reformat a numeric field in Linq
- Linq to XML - Trying to select multiple nodes
- LinqtoSQL filter and order by syntax
- Eager loading / prefetching many-to-many without LoadOptions - Linq to Sql
- Using subquery in entity framework
- How do I aggregate joins?
- query using function “SUBSTR” of Firebird
- How can I fix linq query to select count of ids with group by?
- Convert a List of object to a Tuple array
- Catch the error from Stored Procedure in C#
- LINQ; Select Groups of Lines from a Text File
- c# Sorting a Custom List
- Data annotation issue in EF
- Handling null values for C# linq where query
- Find items that are similar amongst them in List in C# with nested For loops and Linq
- How to change sql query left join to linq query
- LINQ to SQL join two tables to select parent table twice based on two different columns from child table
- Linq Grouping with Include
- Addicted to LINQ
- Split - Join, Aggregate, Zip, LINQ
- Working LINQ query does not work in unit test
- How to get average of list within lists using linq?
- Cannot convert IQueryable<IEnumerable<string>> to return type IEnumerable<string>
- LINQ - How to sum all columns of filtered dataset
- 'Client side GroupBy is not supported.'
- How to get the Entity-SQL command text by LINQ query?
- MVC Update view with uploaded file
- Get top 5 records based on average c# linq lazy loading