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?
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!