Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do you perform a left outer join using linq extension methods

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(???) 
like image 486
LaserJesus Avatar asked Feb 25 '09 05:02

LaserJesus


People also ask

How left outer join implement in LINQ?

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.

How Use left and right join in LINQ?

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".

What are extension methods in LINQ?

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.


2 Answers

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}); 
like image 89
Marc Gravell Avatar answered Sep 23 '22 10:09

Marc Gravell


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.

like image 27
Ocelot20 Avatar answered Sep 22 '22 10:09

Ocelot20