LINQ查询检查null

use*_*b00 4 linq linq-to-sql

我有一个userList,有些用户没有名字(null).如果我运行第一个LINQ查询,我得到一个错误说"对象引用未设置为对象的实例"错误.

var temp = (from a in userList
            where ((a.name == "john") && (a.name != null))
            select a).ToList();
Run Code Online (Sandbox Code Playgroud)

但是,如果我通过在前面检查null来切换顺序,那么它可以正常运行而不会抛出任何错误:

var temp = (from a in userList
            where ((a.name != null) && (a.name == "john"))
            select a).ToList();
Run Code Online (Sandbox Code Playgroud)

这是为什么?如果那是纯粹的C#代码(不是LINQ),我认为两者都是一样的.我没有SQL分析器,我只是好奇它们在SQL级别上被翻译时会有什么不同.

Mar*_*ers 11

在C#中,&&运算符是短路的,因此如果第一个条件返回false,则根本不执行第二个条件.来自MSDN:

条件AND运算符(&&)执行其bool操作数的逻辑AND,但仅在必要时才计算其第二个操作数.

||运营商的行为以类似的方式,但它并没有评估它的第二个参数,如果第一个返回true.


我不认为这是完整的故事.我的帖子的其余部分包括以下几点:

  • 您可以使用DataContext.Log记录SQL语句.
  • 无论你在哪个方向写它,你的查询都不应该生成错误.
  • LINQ与对象和LINQ to SQL之间的行为存在差异.
  • 您的过滤可能是在本地执行而不是在数据库中执行.

您可以在Visual Studio中轻松查看生成的SQL,而无需SQL分析器.您可以将鼠标悬停在LINQ to SQL查询对象上,它将显示SQL.或者您可以使用它DataContext.Log来记录SQL语句,例如:

TextWriter textWriter = new StringWriter();
using (var dc = new UserDataContext())
{
    dc.Log = textWriter;
    var userList = dc.Users;
    var temp = (from a in userList
                where (a.Name.ToString() == "john") && (a.Name != null)
                select a).ToList();
}
string log = textWriter.ToString();
Run Code Online (Sandbox Code Playgroud)

您还可以登录到文件,甚至可以Console.Out:

dc.Log = Console.Out;
Run Code Online (Sandbox Code Playgroud)

执行此操作您可以看到查询看起来像这样,尽管您可能在选择列表中有更多列:

SELECT [t0].[Name]
FROM [dbo].[User] AS [t0]
WHERE ([t0].[Name] = @p0) AND ([t0].[Name] IS NOT NULL)
Run Code Online (Sandbox Code Playgroud)

另一点是您的查询不应生成错误.即使a.name是null,a == "john"仍应该工作 - 它只会返回false.

最后,C#通常如何工作以及LINQ to SQL如何工作之间存在差异.您不应该从数据库中获取null异常.为了证明这一点,我将对您的查询进行一些小修改 - 添加一个ToStringa.Name:

var temp = (from a in userList
            where (a.Name.ToString() == "john") && (a.Name != null)
            select a).ToList();
Run Code Online (Sandbox Code Playgroud)

现在,对于具有NullReferenceException的对象,Linq会失败,但它可以在不抛出异常的情况下使用LINQ to SQL.所以我怀疑你已经将数据库中的所有项目加载到内存中并在本地过滤.换句话说,也许你有这样的事情:

var userList = dc.Users.ToList();
Run Code Online (Sandbox Code Playgroud)

而不是允许数据库进行过滤的以下内容:

var userList = dc.Users;
Run Code Online (Sandbox Code Playgroud)

所以我怀疑这个问题还有什么比满足于眼睛的要多.也许你可以提供更多细节.