【问题标题】:LINQ join query returning nullLINQ 连接查询返回 null
【发布时间】:2017-01-01 16:49:28
【问题描述】:

我有三张桌子。

表 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,而是一个空集合。 Linq 查询不返回 null(除非您从中检索到可能为空的特定记录)

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


【解决方案1】:

您应该避免将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()

...

为了理解为什么会这样,当bdatanull 时尝试评估where bdata.Active == true(即没有匹配的记录)。实际上,如果这是 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

...

【讨论】:

  • 不是那么明显 - 当连接右侧没有匹配记录时,bdatanull,因此 where bdata.Active = true 计算结果为 false 并阻止查询返回记录。
  • 如果 linq 中有 10 个 left join,就会出现性能问题
  • 我不这么认为。连接数无关紧要。在加入之前进行过滤总是有帮助的。即使没有,产生正确的结果总是比产生更快但不正确的结果更高的优先级。
  • 根据我使用 EF 的经验,选项 (2) 将产生最好的 SQL。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-05-10
  • 2018-03-05
  • 1970-01-01
  • 2020-09-27
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多