Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How do typehandlers in F# work? #88

Open
dredgy opened this issue Jun 15, 2023 · 0 comments
Open

How do typehandlers in F# work? #88

dredgy opened this issue Jun 15, 2023 · 0 comments

Comments

@dredgy
Copy link

dredgy commented Jun 15, 2023

Sorry, this is not an issue with Dapper.Fsharp but I'm creating a new library that has some overlap and would be appreciative of any help you could offer. I'm not very familiar with Dapper and am considering using a custom approach but going to try to stick with Dapper for now.

I have created a custom type handler for a generic union type and whilst parseValue is being called and working correctly on select, setValue is never being called.

Is there anything special I have to do? I have defined it as such.

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

[<CLIMutable>]
type Address = {
    id: PrimaryKey<Address>
    address: string
} with
    static member DatabaseTable = "addresses"

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

    override _.SetValue(param, value) =

        let valueOrNull =
            match value with
            | PrimaryKey.Id x -> box x
            | EmptyPrimaryKey -> DBNull.Value

        param.Value <- valueOrNull

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

And registering it as such

   let PKeyHandler = typedefof<PrimaryKeyHandler<_>>

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

            let pkt = typedefof<PrimaryKey<_>>.MakeGenericType(t)
            SqlMapper.AddTypeHandler(pkt, (ctor :?> SqlMapper.ITypeHandler))
        )

Anything jump out? I'm hoping I've just made a simple blunder. Do I have to register each union case a separate typehandler? That seems gross, and the optionHandler works fine so wouldn't think so

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant