1

我有一个类似于以下的 SQL 语句:

SELECT DATEDIFF(Day, startDate, endDate) FROM Data WHERE ProjectId=@id

Data没有任何记录的情况下ProjectId,SQL Server 返回 null。

在 Dapper 中,我通过以下方式执行此操作:

value = conn.Query<int>("...").SingleOrDefault()

在这种情况下,我希望 的语义SingleOrDefault意味着“如果这是 null,则返回零”。事实上,我的代码更加零友好:

int toReturn = 0;
using (var conn = ...) {
  toReturn = conn.Query<int>("SELECT DATEDIFF(...))");
}
return toReturn;

当我调试并单步执行此代码时,我发现该行yield return (T)func(reader)正在引发空指针异常。

我在这里做错了什么,还是设计使然?

(仅供参考,解决方法是将我的选择包装在一个ISNULL(..., 0)

4

1 回答 1

3

如果 Data 没有 ProjectId 的任何记录,SQL Server 将返回 null。

Data没有任何匹配记录的情况下,SQL Server 不会真正返回 null - 它不返回任何行。这种情况很好用:

var result = connection.Query<int>( // case with rows
 "select DATEDIFF(day, GETUTCDATE(), @date)", new { date = DateTime.UtcNow.AddDays(20) })
 .SingleOrDefault();
result.IsEqualTo(20);

result = connection.Query<int>( // case without rows
    "select DATEDIFF(day, GETUTCDATE(), @date) where 1 = 0", new { date = DateTime.UtcNow.AddDays(20) })
    .SingleOrDefault();
result.IsEqualTo(0); // zero rows; default of int over zero rows is zero

两者都工作正常。您说ISNULL“修复”的事实意味着您正在谈论不同的场景 - “我返回行”场景。既然是这种情况,您的代码所说的是“取这个包含 null 的 1 个或多个整数,并将其映射为不可为 null 的 int” - 这是不可能的,并且映射器是正确的抛出一个例外。相反,你想要的是:

int? result = connection.Query<int?>(...).SingleOrDefault();

现在,如果有行,它会将值映射到int?然后应用单或默认值。如果你想要它作为一个 int,那么也许:

int result = connection.Query<int?>(...).SingleOrDefault() ?? 0;

如果您需要能够区分“零行”和“空结果”,那么我建议:

class NameMe {
    public int? Value {get;set;}
}
var row = connection.Query<NameMe>("select ... as [Value] ...", ...)
                    .SingleOrDefault();
if(row == null) {
   // no rows
} else if(row.Value == null) {
   // one row, null value
} else {
   // one row, non-null value
}

或类似的东西

于 2012-10-29T20:21:52.147 回答