efcore / EFCore.FSharp

Adds F# design-time support to EF Core
MIT License
228 stars 26 forks source link

Support for empty discriminated union #147

Open EspenBrun opened 1 year ago

EspenBrun commented 1 year ago

Hello,

Thanks for this awesome package!

Is your feature request related to a problem? Please describe. I would like to use an empty discriminated union to hold in my records

type BlogType
    | Essay
    | Long

Describe the solution you'd like Something like registerEmptyUnionCases(), so I can just use mye EquineBeast DU as normal in by fsharp code.

If a define an Enum, it will be stored as 0, 1, 2 in the database.

Describe alternatives you've considered If I could define a value converter on the ModelSnapshot that would also solve my problem (although registering in _.OnConfigure once would be much preferred). I have tried something like this with no luck (does not compile)

            b.Property<BlogType>("BlogType")
                .HasMaxLength(16)
                .HasColumnType("char(16)")
                .HasConversion (fun v -> v.ToString(), fun v -> BlogType.fromString v)
                |> ignore
EspenBrun commented 1 year ago

This works

let duValueConverter<'a> =
   ValueConverter<'a, string>((fun v -> v.ToString()), (fun v -> fromStringOrFail<'a>(v)))

and

            b.Property<BlogType>("BlogType")
                .HasConversion (duValueConverter<BlogType>)
                |> ignore

Would still be nice to just have a registerEmptyUnionCases() that handled this for every empty DU

EspenBrun commented 11 months ago

The fromStringOrFail utility for anyone intersted:

// utility
let inline fromStringOrFail<'a> (s: string) =
    let duType = typeof<'a>

    match
        FSharpType.GetUnionCases duType
        |> Array.filter (fun case -> case.Name = s.Replace(" ", ""))
    with
    | [| case |] -> FSharpValue.MakeUnion(case, [||]) :?> 'a
    | _ -> failwith $"Could not parse {s} to {duType.Name}"