linq join查询返回null

时间:2016-08-25 09:58:52

标签: entity-framework linq asp.net-mvc-5

我有三张桌子 表A

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

表c

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

about查询给出null。在调试变量res上有null。

1 个答案:

答案 0 :(得分:3)

您应避免将where条件放在来自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 == truebdata时尝试评估null(即没有匹配的记录)。实际上,如果这是LINQ to Objects,则上述标准将生成NullReferenceException。但是LINQ to Entities可以处理那些没有异常,因为数据库在查询通常不可为空的列时自然支持null值。所以上面的简单计算结果为false,因此过滤结果记录并有效地消除left outer join的影响,根据定义,它应返回左侧记录,而不管是否存在匹配的右侧记录。

这意味着实际上有第三种方式(虽然前两个选项更可取) - 包括明确的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

...