我有一个类似于:
的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)
)
答案 0 :(得分:2)
如果Data没有ProjectId的任何记录,SQL Server将返回null。
在Data
没有任何匹配记录的情况下,SQL服务器实际上不返回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或更多整数,并将其映射为不可为空的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
}
或类似的东西