System.Data.SqlClient.SqlException Thrown by Dapper When Query Result Has More Than 1000 Records

c# dapper dapper-extensions sql sql-server

Question

The method call below fails with the message "The conversion of a varchar data type to a datetime data type resulted in an out-of-range value.":

public IEnumerable<SomeResult> GetResults(SqlConnection connection, string attribute)
    {
        var sql = string.Format(@"
        SELECT TOP 2000
            r.Id
            ,r.LastName
            ,r.FirstName
            ,r.Ssn
            ,r.CurrentId
            ,BeginDate = case when isdate(rli.BeginDate) = 1 then convert(datetime, rli.BeginDate) else NULL end
            ,EndDate = case when isdate(rli.EndDate) = 1 then convert(datetime, rli.EndDate) else NULL end
            ,rli.LcknTyCd
            ,rli.ProvId
        FROM 
            [dbo].[Span] rli
            INNER JOIN [dbo].Recipient r
                ON rli.SysId = r.SysId
            INNER JOIN [dbo].ValidRecipient lc
                ON r.SysId = lc.SysId
        WHERE 
            BeginDate <= GETDATE()
            AND EndDate >= GETDATE()
            AND rli.LcknTyCd = @LcknTyCd);

        return connection.Query<SomeResult>(sql, new { LcknTyCd = attribute}).ToList();
    }

public struct SomeResult
{
    public string Id{ get; set; }
    public string LastName { get; set; }
    public string FirstName { get; set; }
    public string Ssn { get; set; }
    public string CurrentId{ get; set; }
    public DateTime? BeginDate { get; set; }
    public DateTime? EndDate { get; set; }
    public string LcknTyCd{ get; set; }
    public string ProvId{ get; set; }
}

If the result set contains 1000 (or fewer) records, the code works correctly. When I execute the query in SQL Server Management Studio (2014 edition), I don't get an error either. Even when I remove the TOP from the select and execute it in SSMS, no error occurs (12,000+ records are returned, as expected).

What should I be doing instead of the above implementation to successfully retrieve result sets with more than 1000 rows? Would a stored procedure be more appropriate in this case?

Accepted Answer

Sounds like your date fields are stored in a varchar column. Ideally, you should change those to datetime fields. If that's not an option, change your WHERE clause to look like this:

WHERE 
  case when isdate(rli.BeginDate) = 1 then convert(datetime, rli.BeginDate) else NULL end <= GETDATE()
  AND case when isdate(rli.EndDate) = 1 then convert(datetime, rli.EndDate) else NULL end >= GETDATE()
  AND rli.LcknTyCd = @LcknTyCd);

The reason it succeeded on your top 1000 query is likely because the top 1000 records found all contained valid dates.


Expert Answer

That is a database server error: dapper doesn't know about varchar and doesn't take in terms of varchar - it talks about .net Strings. So: one of your dates-stored-as-varchar is broken and does not contain a valid value.

Basically: try this query in SSMS: I expect it will break there too!

Changing to a stored procedure will not change this at all. What needs to change is the broken data - and (more importantly) the bad choice of storing date/time data in a text-based column.




Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Is this KB legal? Yes, learn why
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Is this KB legal? Yes, learn why