2010-05-16 152 views
3

我有一个userList,有些用户没有名称(空)。如果我运行第一个LINQ查询,我得到一个错误,说“对象引用未设置为对象的实例”错误。LINQ查询检查为空

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

但是,如果我通过将检查空门前切换顺序,然后它不抛出任何错误:

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

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

回答

10

在C#中,&& operator是短路的,所以如果第一个条件返回false,则根本不会执行第二个条件。从MSDN:

The conditional-AND operator (&&) performs a logical-AND of its bool operands, but only evaluates its second operand if necessary.

|| operator的行为以类似的方式,只是它不评估,如果第一个返回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(); 

您也可以登录到一个文件甚至Console.Out

dc.Log = Console.Out; 

这样做,你可以看到,查询看起来像这样,虽然你可能会有更多的列在选择列表:

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

另一点是,您的查询不应该产生一个错误。即使a.name为空,a == "john"仍然可以工作 - 它只会返回false。

最后,C#的正常工作方式与LINQ to SQL的工作方式有所不同。你不应该从数据库中得到一个空的异常。为了证明这一点,我会做一个小的修改您的查询 - 添加ToStringa.Name

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

现在这个失败对LINQ与一个NullReferenceException对象,但它与LINQ工作没有抛出异常的SQL。所以我怀疑你已经把数据库中的所有项目加载到内存中,并在本地进行过滤。换句话说,也许你有这样的事情:

var userList = dc.Users.ToList(); 

,而不是这将使数据库做过滤以下:

var userList = dc.Users; 

所以我怀疑还有更多的这个问题比满足眼。也许你可以提供更多的细节。

+0

很好的回答 - 甜蜜和简单的 – 2010-05-16 01:57:17

+0

非常感谢...... – userb00 2010-05-16 01:59:37

+0

@Preet僧伽:不再那么短。仔细看看它,我不确定简单的答案能够充分解释行为。 – 2010-05-16 02:23:37

0

关于这个问题,如何转换SQL - 我认为SQL具有相同的短路语义,所以SQL转换器只保留生成的查询中的条件顺序。

例如以下两个LINQ条款:

where p.CategoryID != null && p.CategoryID.Value > 1 
where p.CategoryID.Value > 1 && p.CategoryID != null 

Translet以下两个SQL子句:

WHERE ([t0].[CategoryID] IS NOT NULL) AND (([t0].[CategoryID]) > @p0) 
WHERE (([t0].[CategoryID]) > @p0) AND ([t0].[CategoryID] IS NOT NULL) 
+0

我不认为SQL具有与C#相同的短路语义。看到这个问题http://stackoverflow.com/questions/2842334/linq-query-checks-for-null/2842340#2842340和这篇文章:http://weblogs.sqlteam.com/mladenp/archive/2008/02/ 25/How-SQL-Server-short-circuits-WHERE-condition-evaluation.aspx – 2010-05-16 02:55:57

+0

@Mark:有趣的 - 在这种情况下可能并不重要,因为SQL查询在处理'null'时不会失败。 。 – 2010-05-16 12:56:34