2016-08-25 8 views
0

У меня есть три таблицы.
Таблица Alinq join query return null

id name des   table2  table3 
1 xyz TableA_des1 null  1 
2 abc TableA_des2 1   2 
3 hgd TableA_des2 2   3 

Таблица B

id name des   Active 
1 xyz TableB_des1 1 
2 abc TableB_des2 1 
3 hgd TableB_des2 1 

Таблица с

id name des   Active 
1 xyz TableC_des1 1 
2 abc TableC_des2 1 
3 hgd TableC_des2 1 

Linq запрос

var res = (from a in TableA 
       where id = 1 

       join b in TableB on a.table2 equals b.id into ab 
       from bdata in ab.DefaultIfEmpty() 
       where bdata.Active = true 

       join c in TableC on a.table3 equals c.id into ac 
       from cdata in ac.DefaultIfEmpty() 
       where cdata.Active = true 

       select new { data1 = a.name, data2 = bdata?? string.Empty, data3 = cdata?? string.Empty}) 

о запросе дает нуль. при отладке переменной res имеет значение NULL.

+1

, которая не возвращает 'null' но пустая коллекции. Запросы Linq не возвращают 'null' (если вы не извлекли из него определенную запись, которая может быть нулевой) –

ответ

3

Вам следует избегать установки условий на переменные диапазона, поступающие с правой стороны от left outer join, так как это эффективно превращает их в inner join.

Вместо этого, вы должны либо применить правую сторону фильтрации перед тем объединения:

from a in TableA 
where id = 1 

join b in TableB.Where(x => a.Active) 
on a.table2 equals b.id 
into ab 
from bdata in ab.DefaultIfEmpty() 

join c in TableC.Where(x => x.Active) 
on a.table3 equals c.id 
into ac 
from cdata in ac.DefaultIfEmpty() 

... 

или включить их в соединении (если это возможно):

from a in TableA 
where id = 1 

join b in TableB 
on new { id = a.table2, Active = true } equals new { b.id, b.Active } 
into ab 
from bdata in ab.DefaultIfEmpty() 

join c in TableC 
on new { id = a.table3, Active = true } equals new { c.id, c.Active } 
into ac 
from cdata in ac.DefaultIfEmpty() 

... 

Для того, чтобы понять, почему это, попытайтесь оценить where bdata.Active == true, когда bdata - null (т. е. нет соответствующей записи). На самом деле, если это LINQ to Objects, приведенные выше критерии будут генерировать NullReferenceException. Но LINQ to Entities может обрабатывать эти исключения без учета, поскольку базы данных, естественно, поддерживают значения null в запросах для столбцов, которые обычно не имеют значения NULL. Таким образом, приведенное выше значение оценивается как false, следовательно, фильтрует результирующую запись и эффективно удаляет эффект left outer join, который по определению должен возвращать левую запись независимо от того, существует ли соответствующая правая боковая запись.

Это означает, что на самом деле есть третий путь (Althought первые два варианта является более предпочтительным) - включает явный null проверку:

from a in TableA 
where id = 1 

join b in TableB 
on a.table2 equals b.id 
into ab 
from bdata in ab.DefaultIfEmpty() 
where bdata == null || bdata.Active 

join c in TableC 
on a.table3 equals c.id 
into ac 
from cdata in ac.DefaultIfEmpty() 
where cdata == null || cdata.Active 

... 
+0

он работает, может подробно описать ур ответ – anand

+0

Не так ли очевидно - когда нет соответствующей записи с правой стороны join, 'bdata' является' null', поэтому 'where bdata.Active = true' оценивает' false' и не позволяет запросу возвращать записи. –

+0

если 10 левых объединений в linq, будет проблема с перфомансом – anand