Search code examples
c#.netlinqleft-join

Linq Left Join Fails on List when right side is empty


I'm trying to perform a left join on 2 lists, I'm running into a problem with my query where the left join fails if the right list is empty. How can I change the query so the left join will still work even if the list is empty

Example query:


var received = new List<Foo>{new Foo{ProductId=1,WarehouseSectionId=2, qty= 7}};
var reserved = new List<Foo>{};
var leftOuterJoin = from r in received
                    join rs in reserved.DefaultIfEmpty()
                    on new {a = r.ProductId, b = r.WarehouseSectionId } equals new { a = rs.ProductId, b =  rs.WarehouseSectionId } into joinedL
                    from rs in joinedL.DefaultIfEmpty()
                    select new Foo{
                    qty =  rs != null ? r.qty + rs.qty: r.qty};

.NetFiddle Implementing the problem https://dotnetfiddle.net/Brh74F

Right now I can avoid this issue with a if statement but I would really like to be able to implement a proper left join in pure linq.


Solution

  • Remove .DefaultIfEmpty() in

    join rs in reserved.DefaultIfEmpty()
    

    The reason why remove .DefaultIfEmpty() as:

    public static System.Collections.Generic.IEnumerable<TSource> DefaultIfEmpty<TSource> (this System.Collections.Generic.IEnumerable<TSource> source, TSource defaultValue);
    

    Returns

    IEnumerable<TSource> An IEnumerable that contains defaultValue if source is empty; otherwise, source.

    Since you didn't pass defaultValue to .DefaultIfEmpty(), it will return null when reserved is empty list.

    And select r since you want to return data from the LEFT table.

    var leftOuterJoin = from r in received
                        join rs in reserved
                        on new { a = r.ProductId, b = r.WarehouseSectionId } equals new { a = rs.ProductId, b =  rs.WarehouseSectionId } into joinedL
                        from rs in joinedL.DefaultIfEmpty()
                        select r;
    

    Sample program


    Updated:

    In case you are accessing RIGHT table (rs), you need to do null checking for rs first and next handling for null case.