tags:

views:

109

answers:

3

Given a classic DB structure of Orders has zero or more OrderLines and OrderLine has exactly one Product, how do I write a linq query to express this?

The output would be

OrderNumber - OrderLine - Product Name
Order-1       null        null // (this order has no lines)
Order-2       1           Red widget

I tried this query but is not getting the orders with no lines

var model = (from po in Orders
             from line in po.OrderLines
                select new
                {
                    OrderNumber = po.Id,
                    OrderLine = line.LineNumber,
                    ProductName = line.Product.ProductDescription,
                }
             )

I think that the 2nd from is limiting the query to only those that have OrderLines, but I dont know another way to express it. LINQ is very non-obvious if you ask me!

+2  A: 

Here is an article which appears to explain how to achieve exactly what you are trying to do.

NickLarsen
+1 It's called an Outer Join.
Robert Harvey
And here I was googling "LINQ INNER JOIN" (doh!). Is it OK to use join and defaultifempty()? I saw this blog post saying it wasnt a good idea: http://blogs.teamb.com/craigstuntz/2010/01/13/38525/ (but he didnt give a outer join example)
JK
It is plenty okay to use `DefaultIfEmpty()` as long as having a default value does not break the semantics of your solution.
NickLarsen
A: 

This is the working query (built using the example linked above):

var model = (from po in orders
             join line in orderLines // note this is another var, it isn't po.Lines
             on po.Id equals line.OrderId into g
             from line in g.DefaultIfEmpty()
            select new
            {
                OrderNumber = po.Id,
                OrderLine = line == null ? 0 : line.LineNumber,
                ProductName = line == null ? string.Empty : line.Product.ProductDescription,
            }
         )
JK
A: 
var model =
  from po in Orders 
  from line in po.OrderLines.DefaultIfEmpty()
  select new
  { 
    OrderNumber = po.Id, 
    OrderLine = line != null ?
      (int?)line.LineNumber : null, 
    ProductName = line != null ?
       line.Product.ProductDescription : null 
  } ;
David B