Entity Framework Core : Apply Conversion to all properties of type Option in F#

entity-framework-core f# option-type

Question

I'm using Entity Framework Core 2.1 in F#.
I want to setup a generic type conversion for Option types so that EF knows how to handle them.

I found this very helpful post that shows how to setup a generic convertor for Option types.
So here's what I have so far (putting snippits together)

[<Table("Users", Schema = "pm")>]
type [<CLIMutable>] User = {
  [<DatabaseGenerated(DatabaseGeneratedOption.Identity)>]
  UserID           : int64
  FirstName        : string
  LastName         : string
  LastLoggedInTime : DateTimeOffset option
}
with
  static member Configure (mb : ModelBuilder) =
    mb.Entity<User>()
      .Property(fun p -> p.LastLoggedInTime)
      .HasConversion(OptionConverter<DateTimeOffset>()) |> ignore

This is great, except if I add a new property to my type. I will need to add the last three lines of the above code for that property as well. I'm looking for a way to do it for all properties all at once :D

So then I found this helpful SO answer that lead me to the below code

let tt = mb.Model.GetEntityTypes()
         |> Seq.map(fun et -> et.GetProperties()) |> Seq.concat
         |> Seq.filter(fun p -> p.ClrType = typeof<Option<DateTimeOffset>>)
         |> Seq.map(fun p -> mb.Entity(p.DeclaringEntityType.ClrType)
                               .Property(p.Name)
                               .HasConversion(OptionConverter<DateTimeOffset>()))

Now the problem that I'm trying to solve is to figure out how to make this code work with Generic types so I don't have to specify the type. I want it to be something like p.ClrType = typeof<Option<T'>> and at the end, something like .HasConversion(OptionConverter<T'>())

Any thoughts?

1
2
9/28/2018 1:45:00 PM

Accepted Answer

so going off your initial question "I want to setup a generic type conversion for Option types so that EF knows how to handle them." I am assuming you mean you want EF to properly map an option to a "NULL" column of the corresponding base type, and that you are having problems because EF doesn't know how to handle FSharp.Option?

You could instead just use Nullable in place of Option for your EF types, and it will resolve as it does in C#.

So for instance, your example type becomes:

type [<CLIMutable>] User = {
  [<DatabaseGenerated(DatabaseGeneratedOption.Identity)>]
  UserID           : int64
  FirstName        : string
  LastName         : string
  LastLoggedInTime : Nullable<DateTimeOffset>
}

For types that can not be Nullable but are Options in your domain (strings for example), you just set them as their base type and it will work just fine.

If you are mapping to F# domain types somewhere else, you can just use Option.ToNullable and Option.OfNullable there, or map None to null if the type cannot be nullable as stated above.

Hope this helps!

2
9/28/2018 4:50:59 PM


Related Questions





Related

Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow