0

In the code below, I'm wondering why the elements resulting from my left outer join (as in from d in co.DefaultIfEmpty(emptyOrder) where d is the elements of the table returned from co.DefaultIfEmpty(emptyOrder)) don't contain properties from both Customers and Orders, but rather only contains properties from Orders. I find myself having use two variables to display the required information, c.c and c.d, to be able to access information from Customers and Orders. If I replace c.c.CompanyName by c.d.CompanyName, the compiler says CompanyName is not a property of c.d, which is an Order. What I don't understand is this: isn't d supposed to be an element of the resulting table from joining Customers and Orders? Why then doesn't d contain properties from both Customers and Orders as in SQL where the resulting joined table would display columns from Customers and Orders all into one table?

var query11 = from c in CustomerList
                      where c.Country == "USA"
                      join o in OrderList 
                          on c.CustomerID equals o.CustomerID into co
                      from d in co.DefaultIfEmpty(emptyOrder)
                      select new { c, d };

foreach (var c in query11) {
                sbResult.Append(String.Format("CustID = {0}, Name = {1}, 
                OrderID = {2}, OrderDate = {3:d}\r\n",
                   c.c.CustomerID, c.c.CompanyName, c.d.OrderID, 
                   c.d.OrderDate));
}
Quoc-Minh
  • 113
  • 3
  • 9

1 Answers1

0

What you're seeing is normal. The whole mass of LINQ there is the left outer join. If you hover the mouse over co, its type is IEnumerable<Order> (or whatever the name of the item class in OrderList is).

The "joined thing" with the properties of both is the anonymous type you select at the end -- all examples of this LINQ left outer join technique return an anonymous type with the "left table" object and the "right table" object -- or else with various properties pulled from each. As in SQL, the fields in the result set are determined by what you select.

You could change select new { c, d } to select new { c.CustomerID, c.CompanyName, d.OrderID, d.OrderDate } and get a cleaner anonymous type for your loop.

  • But why does d represent only an Order item when d is an element of the co.DefaultIfEmpty() return. Isn't co the result table from the join? – Quoc-Minh Nov 01 '17 at 03:47
  • Hover the mouse over co. co.DefaultIfEmpty() returns Order; there’s nothing else in an enumeration of Order. That’s how join works in LINQ. If you just want someone from Microsoft to explain the thinking behind the design of LINQ join, you should say so in your question. I’ll delete my answer if it doesn’t address what you’re looking for. – 15ee8f99-57ff-4f92-890c-b56153 Nov 01 '17 at 03:48
  • Your answer was very helpful. The only thing that was left to understand was what DefaultIfEmpty() returns. The DefaultIfEmpty() function only checks for nulls in the right table, in this case the OrderList's from each customer, and returns all sequences of Orders with nulls defaulted. The msdn link you have provided me answered the question at "In this example, DefaultIfEmpty is called on each sequence of matching Pet objects." Where we left outer join to a Person collection a Pet collection. – Quoc-Minh Nov 01 '17 at 03:59