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 の場合は 0 を返す」という意味になると思います。実際、私のコードはさらにゼロフレンドリーです。

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

データにProjectIdのレコードがない場合、SQLServerは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つ以上の整数を取得し、null不可能なintとしてマップする」ということです。これは不可能であり、マッパーは正しくスローします。例外。代わりに、必要なものは次のとおりです。

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

ここで、行がある場合は、値をにマッピングしてからint?、single-or-defaultを適用しますそれをintとして必要な場合は、次のようにします。

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

「ゼロ行」と「null結果」の違いを区別できるようにする必要がある場合は、次のことをお勧めします。

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 に答える