views:

470

answers:

4

I am struggling linq to entities left outer join. I have two entities (tables):

Listings 
{
    ListingID,
    MakeID (nullable)
}

Makes
{
    MakeID,
    Description
}

I want to write something like this in LINQ:

select listings.listingID
,listings.makeid
, IsNull(makes.Description, 'NA')
from listings
left outer join makes
on listings.makeid = makes.makeid
A: 

http://oddiandeveloper.blogspot.com/2008/12/testable-left-outer-join-in-linq-to.html

This should help, it's a blog post I made a while ago, should still be relevant and might help with testability as well.

Also make sure your foreign keys are in place when you generate your entity model, it'll help setup your dependencies.

Odd
+3  A: 

Below is your solution to achieving a left join. In terms of other resources I really recommend trying out linq pad: http://www.linqpad.net/ It is a great learning tool for Linq.

// Listing class/container/table
public class Listing
{
    public string ListingID {get;set;}
    public Int32? MakeID {get;set;}
}

// Make class/container/table
public class Make
{
    public Int32 MakeID {get;set;}
    public string Description {get;set;}
}

public class Main
{
    public static void LinqMain()
    {
        // Populate the listing table with data
        List<Listing> listings = new List<Listing>()
        {
            new Listing() { ListingID = "Test 1", MakeID = 1 },
            new Listing() { ListingID = "Test 2", MakeID = 1 },
            new Listing() { ListingID = "No Make", MakeID = null },
            new Listing() { ListingID = "Test 3", MakeID = 3 },
            new Listing() { ListingID = "Another Makeless", MakeID = null }
        };

        // Populate the makes table with data
        List<Make> makes = new List<Make>()
        {
            new Make() { MakeID = 1, Description = "Make 1"},
            new Make() { MakeID = 2, Description = "Make 2"},
            new Make() { MakeID = 3, Description = "Make 3"},
            new Make() { MakeID = 4, Description = "Make 4"}
        };

        // Return the left join on Make Id
        var result = from l in listings

                     // These two lines are the left join. 
                     join leftm in makes on l.MakeID equals leftm.MakeID into leftm
                     from m in leftm.DefaultIfEmpty()

                     // To ensure the select does not get bogged down with too much logic use the let syntax
                     let description = m == null ? "NA" : m.Description

                     select new { l.ListingID, l.MakeID, description };


    }

The result variable would contain:

  1. { ListingID = "Test 1", MakeID = 1, description = "Make 1" }
  2. { ListingID = "Test 2", MakeID = 1, description = "Make 1" }
  3. { ListingID = "No Make", MakeID = null, description = "NA" }
  4. { ListingID = "Test 3", MakeID = 3, description = "Make 3" }
  5. { ListingID = "Another Makeless", MakeID = null, description = "NA" }
Seravy
@Seravy : Nice verbose answer :)
Pure.Krome
Thanks @Seravybut i got this errorLINQ to Entities does not recognize the method 'System.Collections.Generic.IEnumerable`1[AutoSales.AutoSalesCore.Domain.Impl.Categories] DefaultIfEmpty[Categories](System.Collections.Generic.IEnumerable`1[AutoSales.AutoSalesCore.Domain.Impl.Categories])' method, and this method cannot be translated into a store expression.as DefaultIfEmpty() is not applicable to linq to entities.
Parminder
A: 

Not infront of a dev machine to check, but something like this perhaps?

var x = from l in listings
    join m in makes on l.makeid equals m.makeid into g
    from ma in g.DefaultIfEmpty()
    select new 
    {
        l.listingID, 
        l.makeid, 
        (ma.Description == null ? "NA" : ma.Description)
    };

If you have any trouble with it, let me know and i'll check on my work pc.

Frank Tzanabetis
A: 

Anybody who tells you to use .DefaultIfEmpty() as part of an outer join in LINQ to Entities hasn't actually tried it themselves! Tt simply does not work - at least as at .NET 3.5 SP1.

This blogger tells you how you should actually do it. Essentially, .NET does outer joins in LINQ to Entities by default, so you should leave out the .DefaultIfEmpty(). For multiple outer joins you have to nest the query groups to keep their context clear.

tianvh