'LINQ query with multiple LEFT JOIN
I have 1 main table and 3 tables for ordering the fields in the main table. I return all these tables as lists.
The main table structure is like this:
Color | Make | Country |
---|---|---|
Black | Mercedes | Germany |
Blue | Mercedes | Germany |
Cyan | Mercedes | Germany |
Red | Mercedes | Germany |
Blue | BMW | Germany |
Red | BMW | Germany |
Blue | Toyota | Japan |
Purple | Mercedes | Germany |
And The Ordering tables have Field Names in the main table and another numeric field for their ordering number, an example :
Color | ColorOrder |
---|---|
Black | 6 |
Blue | 2 |
Cyan | 3 |
Red | 4 |
Now I want to order the Main table based on ordering numbers in Ordering Tables in LINQ. In case on the main table if there is no corresponding field in the ordering table then the ordering number should be 0 (In ColorOrdering there is no Purple For example)
Just to be concrete I have made a working sample in Access and Query is as below:
SELECT Cars.Color, Cars.Make, Cars.Country,
IIf([MakeOrder] Is Null,0,[MakeOrder]) AS MkOrder,
IIf([ColorOrder] Is Null,0,[ColorOrder]) AS ClOrder,
IIf([CountryOrder] Is Null,0,[CountryOrder]) AS CntOrder
FROM ((Cars LEFT JOIN ColorOrder ON Cars.Color = ColorOrder.Color)
LEFT JOIN MakeOrder ON Cars.Make = MakeOrder.Make)
LEFT JOIN CountryOrder ON Cars.Country = CountryOrder.Country
ORDER BY
IIf([MakeOrder] Is Null,0,[MakeOrder]),
IIf([ColorOrder] Is Null,0,[ColorOrder]),
IIf([CountryOrder] Is Null,0,[CountryOrder]);
My problem is one of the ordering tables has no records (Country Table). So when I make a join to that table, whatever I do I keep getting,
System.NullReferenceException: 'Object reference not set to an instance of an object.' cntord was null.
Here is my LINQ Query, help on this is much appreciated.
List<CarsWithOrdering> carsWithOrdering = (from c in Cars
//Also tried this, doesn't work
//join cntord in CountryOrderingList.DefaultIfEmpty()
// on c.Country equals cntord.Country
join cntord in CountryOrderingList
on c.Country equals cntord.Country into lcntord
from cntord in lcntord.DefaultIfEmpty()
//........ (Other 2 left joins similar to above one)
select new CarsWithOrdering
{
Color = c.Color,
Make = c.Make,
Country = c.Country,
ColorOrder = int.Parse(colord.ItemValue) ?? 0,
MakeOrder = int.Parse(makord.ItemValue) ?? 0,
CountryOrder = int.Parse(cntord.ItemValue) ?? 0
}).ToList();
Solution 1:[1]
Enumerable.DefaultIfEmpty
Method
public static System.Collections.Generic.IEnumerable<TSource> DefaultIfEmpty<TSource> (this System.Collections.Generic.IEnumerable<TSource> source, TSource defaultValue);
Returns
IEnumerable An IEnumerable that contains defaultValue if source is empty; otherwise, source.
.DefaultIfEmpty()
will return null
when the list is empty.
Solution
Hence, you need to do null
checking for the LEFT JOIN table's value before accessing its properties.
List<CarsWithOrdering> carsWithOrdering = (from c in Cars
join cntord in CountryOrderingList
on c.Country equals cntord.Country into lcntord
from cntord in lcntord.DefaultIfEmpty()
//Other LEFT JOIN tables
select new CarsWithOrdering
{
Color = c.Color,
Make = c.Make,
Country = c.Country,
ColorOrder = colord != null ? int.Parse(colord.ItemValue) : 0,
MakeOrder = makord != null ? int.Parse(makord.ItemValue) : 0,
CountryOrder = cntord != null ? int.Parse(cntord.ItemValue) : 0
})
.ToList();
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | Yong Shun |