我有一个userList,有些用户没有名字(null)。如果我运行第一个LINQ查询,我得到一个错误,说“对象引用未设置为对象的实例”错误。
var temp = (from a in userList
where ((a.name == "john") && (a.name != null))
select a).ToList();
但是,如果我通过在前面检查null来切换顺序,那么它可以工作而不会抛出任何错误:
var temp = (from a in userList
where ((a.name != null) && (a.name == "john"))
select a).ToList();
为什么?如果那是纯粹的C#代码(不是LINQ),我认为两者都是一样的。我没有SQL分析器,我只是好奇它们在SQL级别上被翻译时会有什么不同。
答案 0 :(得分:11)
在C#中&&
operator正在短路,所以如果第一个条件返回false,则根本不执行第二个条件。来自MSDN:
条件AND运算符(&&)执行其bool操作数的逻辑AND,但只在必要时才计算其第二个操作数。
||
operator的行为方式类似,只是如果第一个返回true,它就不会计算第二个参数。
我不认为这是完整的故事。我的帖子的其余部分包括以下几点:
您可以在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的工作方式之间存在差异。您不应该从数据库中获取null异常。为了证明这一点,我将对您的查询进行一些小修改 - 在ToString
之后添加a.Name
:
var temp = (from a in userList
where (a.Name.ToString() == "john") && (a.Name != null)
select a).ToList();
现在,对于具有NullReferenceException的对象,Linq会失败,但它可以在不抛出异常的情况下使用LINQ to SQL。所以我怀疑你已经将数据库中的所有项目加载到内存中并在本地过滤。换句话说,也许你有这样的东西:
var userList = dc.Users.ToList();
而不是允许数据库进行过滤的以下内容:
var userList = dc.Users;
所以我怀疑这个问题还有什么比满足于眼睛的要多。也许你可以提供更多细节。
答案 1 :(得分: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)