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

如何通过反射为程序集中的记录类型批量注册Dapper泛型类型处理器?

批量注册Dapper泛型类型处理器失败问题

我正在做底层逻辑处理,希望这是近期最后一次使用Reflection,之后回归高层开发。

已定义的类型与处理器

首先定义了主键泛型类型:

type PrimaryKey<'x> =
    | Id of int
    | EmptyPrimaryKey

接着定义关联数据库表的记录类型(示例):

type User = {
    user_id: PrimaryKey<User>
    username: string
    email: string
    address_id: PrimaryKey<Address>
} with
    static member DatabaseTable = "users"

为Dapper编写了自定义主键类型处理器:

type PrimaryKeyHandler<'X>() =
    inherit SqlMapper.TypeHandler<PrimaryKey<'X>>()

    (* 暂时不考虑这部分逻辑是否可行 *)
    override _.SetValue(param, value) =
        let valueOrNull =
            match value with
                | PrimaryKey.Id id -> box id
                | EmptyPrimaryKey -> null

        param.Value <- valueOrNull

    override _.Parse value =
        if isNull value || value = box DBNull.Value
        then EmptyPrimaryKey
        else Id (value :?> int)

当前手动注册方式

目前需要为每个含主键的记录类型手动注册处理器:

SqlMapper.AddTypeHandler (PrimaryKeyHandler<User>())
SqlMapper.AddTypeHandler (PrimaryKeyHandler<OtherRecordType>())

批量注册的尝试与错误

我已经能筛选出所有关联数据库表的记录类型:

let RegisterTypeHandlers ()  =
    let assembly = Assembly.GetCallingAssembly()
    let handler = typedefof<PrimaryKeyHandler<_>>

    assembly.GetTypes()
        |> Seq.filter(fun t ->
            FSharpType.IsRecord(t) && t.GetProperty("DatabaseTable") <> null
        )

但尝试遍历这些类型批量调用AddTypeHandler时失败,完整代码如下:

let RegisterTypeHandlers ()  =
    let assembly = Assembly.GetCallingAssembly()
    let handler = typedefof<PrimaryKeyHandler<_>>

    assembly.GetTypes()
        |> Seq.filter(fun t ->
            FSharpType.IsRecord(t) && t.GetProperty("DatabaseTable") <> null
        )
        |> Seq.iter(fun t ->
            printfn $"Type: {t.Name}"
            let ctor = handler
                        .MakeGenericType(t)
                        .GetConstructor(Array.empty)
                        .Invoke(Array.empty)

            
            (typeof<SqlMapper>.GetMethods()
                |> Seq.filter(fun methodInfo ->
                        if methodInfo.Name = "AddTypeHandler" && methodInfo.IsGenericMethodDefinition then
                            let gp = methodInfo.GetParameters()
                            not <| isNull gp && gp.Length = 1 && gp.[0].ParameterType.Name.Contains("TypeHandler")
                        else false)
                |> Seq.head)
                .MakeGenericMethod(t)
                .Invoke(null, [| ctor |]) |> ignore
        )

报错信息:

Unhandled exception. System.ArgumentException: Object of type 'MyModule.Common+PrimaryKeyHandler`1[Program+User]' cannot be converted to type 'Dapper.SqlMapper+TypeHandler`1[Program+User]'.

我研究了反射泛型相关函数,但不知道后续该怎么解决。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.18 05:15:41