简体   繁体   中英

linq to entites left outer join

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

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

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.

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.

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM