I have a SQL statement similar to:
SELECT DATEDIFF(Day, startDate, endDate) FROM Data WHERE ProjectId=@id
In the case where Data doesn’t have any records for ProjectId, SQL Server returns null.
In Dapper, I execute this via:
value = conn.Query<int>("...").SingleOrDefault()
In this case, I expect the semantics of SingleOrDefault to mean “if this is null, return zero.” In fact, my code is even more zero-friendly:
int toReturn = 0;
using (var conn = ...) {
toReturn = conn.Query<int>("SELECT DATEDIFF(...))");
}
return toReturn;
When I debug and step into this code, I find that the line yield return (T)func(reader) is throwing a null pointer exception.
Am I doing something wrong here, or is this by design?
(FYI, the work-around is to wrap my select in an ISNULL(..., 0))
In the case where
Datadoesn’t have any matching records, SQL server does not really return null – it returns no rows. This scenario works fine:both of which work fine. The fact that you say
ISNULL“fixes” it means that you are talking about a different scenario – the “I returned rows” scenario. Since that is the case, what your code is saying is “take this 1-or-more integers which contains a null, and map it as a non-nullable int” – that isn’t possible, and the mapper is correct to throw an exception. Instead, what you want is:Now, if there are rows, it is mapping the value to
int?, and then applying the single-or-default. It you want that as an int, then maybe:If you need to be able to tell the difference between “zero rows” and “null result”, then I would suggest:
or something similar