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。
答案 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 == true
为bdata
时尝试评估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
...