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

ASP.NET Core 6 Web API项目中Dapper不支持TimeOnly类型的解决办法

解决Dapper调用ExecuteScalar时System.TimeOnly参数报错问题

问题场景

在以SQL Server 2016为后端的ASP.NET Core 6 Web API项目中使用Dapper调用ExecuteScalar方法时,出现以下错误:

The member DepartureTime of type System.TimeOnly cannot be used as a parameter value

相关代码及实体类如下:

数据插入代码

public virtual int Create(TModel entity)
{
    int result = -1;
    var insertQuery = QueryGenerator.GenerateInsertQuery(typeof(TModel));
    var factory = new SqlServerDbConnectionFactory(connectionString);
    var profiler = CustomDbProfiler.Current;

    using (var connection = ProfiledDbConnectionFactory.New(factory, profiler))
    {
        try
        {
            if (connection.State == ConnectionState.Closed)
            {
                connection.ConnectionString = connectionString;
                connection.Open();
            }

            result = connection.ExecuteScalar<int>(insertQuery, entity, transaction: null); // 报错位置
        }
        catch (Exception e)
        {
            var sql = profiler.GetCommands();
            throw;
        }
    }

    return result;
}

生成的SQL语句

INSERT INTO [Flight] ([FlightNumber], [SourceCode], [DestinCode],[DepartureTime], [EffectDate], [Stops], [TravelMinutes]) 
VALUES (@FlightNumber, @SourceCode, @DestinCode, @DepartureTime, @EffectDate, @Stops, @TravelMinutes);
SELECT SCOPE_IDENTITY()

FlightModel实体类

public class FlightModel
{
    public int Id { get; set; }
    public string FlightNumber{ get; set; }
    public string SourceCode{ get; set; }
    public string DestinCode { get; set; }
    public TimeOnly DepartureTime{ get; set; }
    public DateOnly EffectDate { get; set; }
    public int Stops{ get; set; }
    public int TravelMinutes { get; set; }
}

解决办法

方案1:自定义Dapper类型处理器(推荐)

由于SQL Server 2016原生不支持.NET 6+的TimeOnly/DateOnly类型,Dapper无法自动完成映射,需要自定义类型处理器实现转换逻辑:

  1. 创建TimeOnly和DateOnly的类型处理器:
// TimeOnly类型处理器
public class TimeOnlyTypeHandler : SqlMapper.TypeHandler<TimeOnly>
{
    public override void SetValue(IDbDataParameter parameter, TimeOnly value)
    {
        // 将TimeOnly转换为SQL Server支持的TimeSpan类型
        parameter.Value = value.ToTimeSpan();
    }

    public override TimeOnly Parse(object value)
    {
        // 将从数据库读取的TimeSpan转换回TimeOnly
        return TimeOnly.FromTimeSpan((TimeSpan)value);
    }
}

// DateOnly类型处理器
public class DateOnlyTypeHandler : SqlMapper.TypeHandler<DateOnly>
{
    public override void SetValue(IDbDataParameter parameter, DateOnly value)
    {
        // 将DateOnly转换为SQL Server支持的DateTime类型
        parameter.Value = value.ToDateTime(TimeOnly.MinValue);
    }

    public override DateOnly Parse(object value)
    {
        // 将从数据库读取的DateTime转换回DateOnly
        return DateOnly.FromDateTime((DateTime)value);
    }
}
  1. 在项目启动时注册这些处理器(比如Program.cs中):
SqlMapper.AddTypeHandler(new TimeOnlyTypeHandler());
SqlMapper.AddTypeHandler(new DateOnlyTypeHandler());

注册后,Dapper会自动处理TimeOnly和DateOnly类型的参数映射,无需修改原有业务代码。

方案2:手动转换参数类型

如果不想全局注册类型处理器,可以在插入时手动将TimeOnly/DateOnly转换为SQL Server支持的类型,使用DynamicParameters传递参数:

public virtual int Create(TModel entity)
{
    int result = -1;
    var insertQuery = QueryGenerator.GenerateInsertQuery(typeof(TModel));
    var factory = new SqlServerDbConnectionFactory(connectionString);
    var profiler = CustomDbProfiler.Current;

    using (var connection = ProfiledDbConnectionFactory.New(factory, profiler))
    {
        try
        {
            if (connection.State == ConnectionState.Closed)
            {
                connection.ConnectionString = connectionString;
                connection.Open();
            }

            // 手动构建参数并转换类型
            var parameters = new DynamicParameters();
            parameters.Add("@FlightNumber", entity.FlightNumber);
            parameters.Add("@SourceCode", entity.SourceCode);
            parameters.Add("@DestinCode", entity.DestinCode);
            parameters.Add("@DepartureTime", ((FlightModel)(object)entity).DepartureTime.ToTimeSpan());
            parameters.Add("@EffectDate", ((FlightModel)(object)entity).EffectDate.ToDateTime(TimeOnly.MinValue));
            parameters.Add("@Stops", entity.Stops);
            parameters.Add("@TravelMinutes", entity.TravelMinutes);

            result = connection.ExecuteScalar<int>(insertQuery, parameters, transaction: null);
        }
        catch (Exception e)
        {
            var sql = profiler.GetCommands();
            throw;
        }
    }

    return result;
}

方案3:升级Dapper版本(辅助)

确保使用的是较新版本的Dapper(2.0+),新版本对.NET 6的新类型有更好的兼容性,但由于SQL Server 2016本身不支持TimeOnly/DateOnly,仍需配合上述类型转换方案使用。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.08 11:35:20