You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SQL Server存储过程DateTime参数不匹配致C#程序崩溃问题

解决Dapper调用SQL Server存储过程时DateTime参数导致的varchar转datetime超出范围错误

问题场景

我创建了一个用于插入学生数据的SQL Server存储过程:

CREATE PROCEDURE ThemHocSinh 
    @TenHS NVARCHAR(255), 
    @NgaySinh DATETIME, 
    @TenChaMe NVARCHAR(255), 
    @SDTChaMe VARCHAR(16), 
    @DiaChi NVARCHAR(255), 
    @LopHC VARCHAR(6) 
AS 
INSERT INTO dbo.HocSinh (MaHS, TenHS, NgaySinh, NgayNhapHoc, TenChaMe, SDTChaMe, DiaChi, LopHC) 
VALUES (DEFAULT, @TenHS, @NgaySinh, DEFAULT, @TenChaMe, @SDTChaMe, @DiaChi, @LopHC)

随后用C#结合Dapper编写了调用方法:

public void ThemHocSinh(string TenHS, DateTime NgaySinh, string TenChaMe, string SDT, string DiaChi, string LopHC) 
{ 
    using (MamNonBK context = new MamNonBK()) 
    { 
        using (IDbConnection db = new SqlConnection(context.Database.Connection.ConnectionString)) 
        { 
            var p = new DynamicParameters(); 
            p.Add("@TenHS", TenHS); 
            p.Add("@NgaySinh", NgaySinh); 
            p.Add("@TenChaMe", TenChaMe); 
            p.Add("@SDTChaMe", SDT); 
            p.Add("@DiaChi", DiaChi); 
            p.Add("@LopHC", LopHC); 
            db.Execute("ThemHocSinh", p, commandType: CommandType.StoredProcedure); 
        } 
    } 
}

但程序运行时崩溃,抛出错误:

System.Data.SqlClient.SqlException: The conversion of a varchar data type to a datetime data type resulted in an out-of-range value. The statement has been terminated.

我的系统日期格式为dd/MM/yyyy,请问该如何解决这个问题?


解决方案

这个错误看起来有点矛盾——毕竟你用的是强类型DateTime参数,按道理Dapper会通过参数化查询直接传递二进制值,不会转成varchar字符串。不过结合错误信息和你的场景,我整理了几个排查和解决的方向:

1. 检查DateTime值是否在SQL Server DATETIME的有效范围内

SQL Server的DATETIME类型有严格的范围限制:1753年1月1日 00:00:00 到 9999年12月31日 23:59:59.997。如果你的代码中传递的是DateTime.MinValue(对应0001年1月1日),或者其他超出这个范围的日期,SQL Server就会抛出这个错误。

解决方法:在调用ThemHocSinh方法前先校验日期值:

if (NgaySinh < new DateTime(1753, 1, 1) || NgaySinh > new DateTime(9999, 12, 31))
{
    throw new ArgumentOutOfRangeException(nameof(NgaySinh), "日期超出SQL Server DATETIME类型的有效范围");
}

2. 显式指定参数的DbType,避免自动推断偏差

虽然Dapper通常能正确推断参数类型,但偶尔会因为环境或文化设置出现偏差。显式指定DbType.DateTime可以强制参数以正确的类型传递:
修改参数添加代码:

p.Add("@NgaySinh", NgaySinh, DbType.DateTime);

3. 确认数据库表的列类型是否正确

检查dbo.HocSinh表的NgaySinh列是否真的是DATETIME类型。如果该列被错误设置为VARCHAR或其他字符串类型,插入时就会发生隐式的varchar转datetime转换,很容易因为格式不匹配触发错误。

你可以用以下SQL语句确认列类型:

SELECT DATA_TYPE 
FROM INFORMATION_SCHEMA.COLUMNS 
WHERE TABLE_NAME = 'HocSinh' AND COLUMN_NAME = 'NgaySinh';

如果结果不是datetime,需要修改表结构:

ALTER TABLE dbo.HocSinh ALTER COLUMN NgaySinh DATETIME;

4. 检查SQL Server的日期格式设置(可选)

如果以上方法都无效,可以检查SQL Server的默认日期格式设置。执行以下SQL查看当前服务器的日期格式:

SELECT DATEFORMAT, @@LANGUAGE;

如果服务器默认的日期格式是mdy(即MM/dd/yyyy),而你传递的日期中日期部分大于12(比如13/01/2024),就会被错误解析为13月,导致超出范围。不过这个问题通常不会出现在参数化查询中,但如果你的存储过程中存在其他隐式转换逻辑,就可能触发。

如果确实是这个原因,你可以在存储过程中显式指定日期格式(不过更推荐保持参数化的方式):

-- 在存储过程中显式转换(仅当必要时)
INSERT INTO dbo.HocSinh (...) VALUES (... CONVERT(DATETIME, @NgaySinh, 103), ...)

其中103对应dd/MM/yyyy格式。

5. 确认DateTime的Kind属性

如果你的NgaySinh是本地时间,但SQL Server期望UTC时间,可能会因为时区转换导致日期超出范围。可以在传递前将日期转换为UTC时间:

var utcNgaySinh = NgaySinh.ToUniversalTime();
p.Add("@NgaySinh", utcNgaySinh, DbType.DateTime);

或者确保SQL Server的时区设置和你的应用一致。

内容的提问来源于stack exchange,提问作者DuckFterminal

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 08:23:14