VB.Net Linq到实体空比较 - '什么都不是'或'=什么都没有'?

5 vb.net linq-to-entities nullable nothing vb.net-2010

我们在VB.Net中有几个项目,使用.Net Framework 4和Linq to Entities来处理我们的许多SQL查询.迁移到EF对我们来说是一个新的转变(已经使用了大约4-6个月),并得到了高层管理人员的支持,因为我们可以更快地编写代码.我们仍然使用很多存储过程,但我们甚至也通过Linq到实体执行这些过程.

我希望清除一些混乱,我找不到一个有意义的直接答案.我们有一些查询,我们想要特定字段具有NULL值的记录.这些是简单的选择查询,没有聚合或左连接等.Microsoft建议查询看起来像这样的MSDN链接:

dim query = from a in MyContext.MyTables
Where a.MyField = Nothing
Select a
Run Code Online (Sandbox Code Playgroud)

我有几个项目,我正是这样做的,它工作得很好,在IDE中没有警告.最近,另一个开发人员创建了一个新项目,当他像上面那样进行空检查时,我们都在IDE中收到此警告:

警告1此表达式将始终计算为Nothing(由于equals运算符的空传播).要检查值是否为null,请考虑使用"Is Nothing".

比较项目,每个都有选项显式和选项严格.如果我们忽略警告,我们会在应用程序运行时获得我们正在寻找的确切记录集.如果我将=符号更改为IS,则警告消失.但为什么这个警告出现在一个项目而不是其他项目?即使在MSDN上也有使用equals运算符的例子,这令人困惑.

Afs*_* Gh 5

生成的列应该是a Nullable(Of T)

所以你可以检查那个字段是否有价值:

dim query = from a in MyContext.MyTables
Where Not a.MyField.HasValue
Select a
Run Code Online (Sandbox Code Playgroud)


Jar*_*Par 2

我相信你在这里看到的是MyField一种Nullable(Of T)类型。可能是一个原始的Integer,Single等等...

您看到此警告的原因是编译器将基本类型的正常相等运算符提升为版本Nullable(Of T)。它本质上执行以下操作

Dim myField As Integer? = a.MyField
Dim other As Integer? = Nothing
If myField = other Then
 ...
End If
Run Code Online (Sandbox Code Playgroud)

但问题是,当它Integer?具有价值时Nothing,它不会与任何东西相比较。因此上述Where子句将始终返回False。编译器试图警告您这个有问题的角落Nullable(Of T),并推动您进行Is Nothing检查,以确定是否a.MyField具有非空值。

这篇博客文章非常详细地解释了为什么会生成此警告及其背后的所有机制。本文是针对 C# 编写的,但基本前提也适用于 VB.Net。