Assuming I have a left outer join as such:
from f in Foo join b in Bar on f.Foo_Id equals b.Foo_Id into g from result in g.DefaultIfEmpty() select new { Foo = f, Bar = result }
How would I express the same task using extension methods? E.g.
Foo.GroupJoin(Bar, f => f.Foo_Id, b => b.Foo_Id, (f,b) => ???) .Select(???)
A left outer join is a join in which each element of the first collection is returned, regardless of whether it has any correlated elements in the second collection. You can use LINQ to perform a left outer join by calling the DefaultIfEmpty method on the results of a group join.
A Left Outer join returns all records from the left table and the matching record from the right table. If there are no matching records in the right table then it returns null. If we want to do a Left Outer join in LINQ then we must use the keyword "into" and method "DefaultIfEmpty".
Extension Methods are a new feature in C# 3.0, and they're simply user-made pre-defined functions. An Extension Method enables us to add methods to existing types without creating a new derived type, recompiling, or modifying the original types.
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});
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With