您当前的位置: 首页 > 

寒冰屋

暂无认证

  • 1浏览

    0关注

    2286博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

如何让 Dapper 支持 DateOnly 类型

寒冰屋 发布时间:2022-06-29 23:00:00 ,浏览量:1

目录

前言

深入探究

调用堆栈

GetDeserializer 方法

AddTypeHandler 方法

实现

结论

 

前言

在上次的文章中,我们让 EF Core 6 支持了 DateOnly 类型。

那么,Dapper 是否支持 DateOnly 类型呢?

public class User
{
    public int Id { get; set; }
    public string Name { get; set; }
    public DateOnly Birthday { get; set; }
}

using (var connection = new SqlConnection(connectionString))
{
    var users = connection.Query("select * from users");
}

也不行:

由于异常提示没有任何指导意义,于是我们想从源码入手解决。

深入探究 调用堆栈

通过调用堆栈,找到发生异常的位置位于SqlMapper.cs第 1113 行:

第 1113 行具体代码如下:

其中func的来源是tuple.Func,而 tuple 是通过如下方式赋值的:

tuple = info.Deserializer = new DeserializerState(hash, GetDeserializer(effectiveType, reader, 0, -1, false));

看到Deserializer这个单词,立刻引起了我们的注意:序列化

GetDeserializer 方法

赶紧来看看GetDeserializer方法的实现:

private static Func GetDeserializer(Type type, IDataReader reader, int startBound, int length, bool returnNullIfFirstMissing)
{
    // dynamic is passed in as Object ... by c# design
    if (type == typeof(object) || type == typeof(DapperRow))
    {
        return GetDapperRowDeserializer(reader, startBound, length, returnNullIfFirstMissing);
    }
    Type underlyingType = null;
    if (!(typeMap.ContainsKey(type) || type.IsEnum || type.IsArray || type.FullName == LinqBinary
        || (type.IsValueType && (underlyingType = Nullable.GetUnderlyingType(type)) != null && underlyingType.IsEnum)))
    {
        if (typeHandlers.TryGetValue(type, out ITypeHandler handler))
        {
            return GetHandlerDeserializer(handler, type, startBound);
        }
        return GetTypeDeserializer(type, reader, startBound, length, returnNullIfFirstMissing);
    }
    return GetStructDeserializer(type, underlyingType ?? type, startBound);
}

方法会从 typeHandlers 中获取ITypeHandler接口的实现。

ITypeHandler接口定义如下:

/// 
/// Implement this interface to perform custom type-based parameter handling and value parsing
/// 
public interface ITypeHandler
{
    /// 
    /// Assign the value of a parameter before a command executes
    /// 
    /// The parameter to configure
    /// Parameter value
    void SetValue(IDbDataParameter parameter, object value);

    /// 
    /// Parse a database value back to a typed value
    /// 
    /// The value from the database
    /// The type to parse to
    /// The typed value
    object Parse(Type destinationType, object value);
}

实现此接口以执行自定义的基于类型的参数处理和值解析

这不正是我们想要的吗?

AddTypeHandler 方法

而怎么向 Dapper 传入ITypeHandler实现呢?

我们最终找到了AddTypeHandler方法:

/// 
/// Configure the specified type to be processed by a custom handler.
/// 
/// The type to handle.
/// The handler to process the .
public static void AddTypeHandler(Type type, ITypeHandler handler) => AddTypeHandlerImpl(type, handler, true);

配置要由自定义处理程序处理的指定类型

实现

首先,创建ITypeHandler实现:

public class DateOnlyTypeHandler : TypeHandler
{
    public override DateOnly Parse(object value)
    {
        return DateOnly.FromDateTime((DateTime)value);
    }

    public override void SetValue(IDbDataParameter parameter, DateOnly value)
    {
        parameter.Value = value.ToDateTime(TimeOnly.MinValue);
    }
}

然后,在启动时添加自定义处理程序:

SqlMapper.AddTypeHandler(new DateOnlyTypeHandler());

现在,程序就可以正常运行了。

结论

今天,我们介绍了使用自定义ITypeHandler来告诉 Dapper 如何处理默认不支持的数据类型。

关注
打赏
1665926880
查看更多评论
立即登录/注册

微信扫码登录

0.0581s