null vs default(decimal?) 设置为 null - 给出不同的结果

null vs default(decimal?) set to null - giving different results

Using: Entity Framework 4.3.1, MVC 4

示例数据库记录(例如):

Id    Height
1     null  
2     2.1

为什么第一个语句返回零结果:

decimal? scannedItemHeight = default(decimal?);

(from st in Stocks
 where st.Height == scannedItemHeight 
 select st.Id).ToList();

但是这条语句returns记录Id 1:

(from st in Stocks
 where st.Height == null
 select st.Id).ToList();

如果 scannedItemHeight 为空,我只想匹配高度也为空的值。

我只想return第一条记录,Id 1.

更新 我最终使用了:

st.Height == scannedItemHeight || (scannedItemHeight == null && st.Height == null)

我之前肯定见过一些奇怪的 LINQ 行为,因为 SQL 处理空值的方式与 C# 处理空值的方式不同。在 C# 中,如果 ab 都为空,则 a == b 为真,而在 SQL 中它们不是……相反,您必须有意识地检查是否为空。我会尝试:

var temp = (from st in Stocks
            where st.Height == scannedItemHeight || (scannedItemHeight == null && st.Height == null)
            select st.Id).ToList();

或以不同方式构造查询:

var filtered = scannedItemHeight == null
    ? Stocks.Where(st => st.Height == null)
    : Stocks.Where(st => st.Height == scannedItemHeight);
var temp = filtered.Select(st => st.Id).ToList();

那是因为在第一种情况下数据库查询类似于

where Height = @param1 ...

而在第二种情况下会是

where Height is null

第一个查询将return没有结果,因为@param1 将为空并且没有行可以匹配这样的条件。

要点是,从 C# 的角度来看,这些查询是等效的,但从 sql 的角度来看,它们不是:您应该在 sql 中使用 IS NULL(或 IS NOT NULL)来检查空值.

如何解决取决于您在参数为空时要执行的操作。对于您的情况:使用 Jon Skeet 的回答

如果有人想要忽略参数并且根本不按它进行过滤(很常见的情况,例如,当参数表示用户在某个字段中的输入时,当没有输入任何内容时 - 没有要过滤的内容),那么请执行以下操作:

where scannedItemHeight == null || st.Height == scannedItemHeight

这将在 sql 喜欢

where @param1 is null OR Height = @param1