如果使用nullable int变量LINQ返回0结果,如果使用“null”则返回准确结果

时间:2011-02-10 04:30:47

标签: c# .net linq-to-sql linq-to-entities

我有一个名为“test”的表,它只有1列,“NullableInt”(可以为null的类型)

记录为:1,2,null

int? nullableInt = null;
var t = db.tests.Where(x => x.NullableInt == null).ToList(); // returns 1 record
var t2 = db.tests.Where(x => x.NullableInt == nullableInt).ToList(); // returns 0 records

由于某种原因,t2返回0条记录,即使它使用的是“nullableInt”变量,其值为null,就像t,它与“null”进行比较

非常感谢任何帮助!

5 个答案:

答案 0 :(得分:6)

是的 - 这是LINQ-to-SQL / Entity Framework中的一个错误。如果您将null硬编码到查询中,而不是当前为空的变量,则只会生成IS NULL个查询。

第二个查询将生成

SELECT .......
WHERE NullableInt == @someParam
WHERE @someParam is null.

第一个将在IS NULL子句中生成相应的WHERE

如果您正在使用LINQ-to-SQL,则可以将查询记录到Console.Out以便自己查看,如果您使用的是EF,那么ToTraceString()应该显示相同的信息(或SQL Server)探查)

答案 1 :(得分:3)

<强> TL;博士

如果在EF6中使用DbContext,则修复此问题。

如果您正在使用EF5(或EF6中的ObjectContext),则需要将ObjectContext.ContextOptions.UseCSharpNullComparisonBehavior设置为true。要在DbContext上执行此操作,请使用以下命令:

((IObjectContextAdapter)db).ObjectContext.ContextOptions.UseCSharpNullComparisonBehavior = true;

更多详情

此问题的根本原因是数据库如何比较空值以及C#如何比较空值的差异。因为您在C#中编写查询,所以您希望使用C#的语义。

在EF5中,我们引入了ObjectContext.ContextOptions.UseCSharpNullComparisonBehavior,它允许您选择使用C#语义而不是数据库语义。默认值为false(以便在升级到EF5时,现有查询不会神奇地开始返回不同的结果)。但您可以将其设置为true,并且您的查询都将返回行。

如果您在EF5中使用DbContext,则需要下拉到ObjectContext进行设置:

((IObjectContextAdapter)db).ObjectContext.ContextOptions.UseCSharpNullComparisonBehavior = true;

如果你使用的是EF6,那么它已经在DbContext上设置为true,所以你很高兴。我们认为这导致了如此多的混乱,值得对现有查询产生潜在影响。

答案 2 :(得分:2)

可以用这种方式构建查询:

var q = db.tests;
if(nullableInt.HasValue)
{
   q = q.Where(x => x.NullableInt == nullableInt.Value);
}
else
{
   q = q.Where(x => x.NullableInt == null);
}
var t2 = q.ToList();

答案 3 :(得分:0)

还有另一种解决方案永远有效,尽管有一点需要注意:

int? nullableInt = null;
var t2 = db.tests.Where(x => object.Equals(x.NullableInt, nullableInt)).ToList();

当值为null时,您将获得正确的IS NULL查询,但是当它不为null时,您将获得类似的内容:

SELECT ...
WHERE ([t0].[NullableInt] IS NOT NULL) AND ([t0].[NullableInt] = @p0) 

显然它有一个额外的条件(其来源有点令人费解)。话虽这么说,SQL Server的查询优化器应该检测到,因为@ p0是一个非空值,第一个条件是超集,并将删除where子句。

答案 4 :(得分:0)

会做:

var t2 = db.tests.Where(x => x.NullableInt == nullableInt ?? null).ToList(); 

工作?

但是,这似乎完全是疯狂的。