F# Options with EF Core
Tags: fsharp, efcore, option
Published: 2018-07-08 22:51:04

---
title: F# Options with EF Core
published: true
tags: fsharp, efcore, option
canonical_url: https://blog.bitbadger.solutions/2018/f-sharp-options-with-ef-core.html
---

**UPDATE:** The code described in this post is now available as a [NuGet package](https://www.nuget.org/packages/FSharp.EFCore.OptionConverter/).

The 2.1 release of [Entity Framework Core](https://docs.microsoft.com/en-us/ef/core/) brought the ability to do [value conversions](https://docs.microsoft.com/en-us/ef/core/modeling/value-conversions). This is implemented through an abstract class, `ValueConverter`, which you can implement to convert a data type. They also provided [several built-in converters](https://docs.microsoft.com/en-us/ef/core/modeling/value-conversions#built-in-converters) that you don’t have to write, such as storing `enum`s as strings. To use a value converter, you provide a new instance of it and attach it to a property in your model’s `OnModelCreating` event.

F# provides an `Option<'T>` type as a way to represent a value that may or may not be present. There are many benefits to defining optional values as `'T option` rather than checking for null; you can [read all about it](https://docs.microsoft.com/en-us/dotnet/fsharp/language-reference/options) if you’d like.

As I was working on a project, I already used `Option.ofObj` to convert my possibly-null results from queries to options; at the field level, though, I was working with default values. Could I use this new feature to handle `null`able columns as well? As it turns out, yes!

Here is the code for the value converter.

```fsharp
module Conversion =

  open Microsoft.FSharp.Linq.RuntimeHelpers
  open System
  open System.Linq.Expressions

  let toOption<'T> =
    <@ Func<'T, 'T option>(fun (x : 'T) -> match box x with null -> None | _ -> Some x) @>
    |> LeafExpressionConverter.QuotationToExpression
    |> unbox<Expression<Func<'T, 'T option>>>
  
  let fromOption<'T> =
    <@ Func<'T option, 'T>(fun (x : 'T option) -> match x with Some y -> y | None -> Unchecked.defaultof<'T>) @>
    |> LeafExpressionConverter.QuotationToExpression
    |> unbox<Expression<Func<'T option, 'T>>>

type OptionConverter<'T> () =
  inherit ValueConverter<'T option, 'T> (Conversion.fromOption, Conversion.toOption)

```

The `Conversion` module contains the functions that we’ll need to provide in the `ValueConverter` constructor. _(With the way class inheritance is coded in F#, and the way `ValueConverter` wants its expressions in its constructor, this is a necessary step. I would have liked to have seen a no-argument constructor and overridable properties as an option, but I’m not complaining; this is a really great feature.)_ Within those functions, we make use of [code quotations](https://docs.microsoft.com/en-us/dotnet/fsharp/language-reference/code-quotations), then convert the quotation expressions to Linq expressions.

One other note; in the `toOption` function, if we used `Option.ofObj` instead of `box x`, the code would not support value types. This means that things like an `int option` field wouldn’t be supported.

Now that we have our option converter, let’s hook it into our model. In my project, each entity type has a static `configureEF` function, and I call those from `OnModelCreating`. Here’s an abridged version of one of my entity types:

```fsharp
[<CLIMutable>]
[<NoEquality>]
[<NoComparison>]
type Member =
  { /// ...
    /// E-mail format
    format : string option
    /// ...
    }
  with
    /// ...
    static member configureEF (mb : ModelBuilder) =
    /// ... HasColumnName statements, etc.
    mb.Model.FindEntityType(typeof<Member>).FindProperty("format").SetValueConverter(OptionConverter<string> ())
    |> ignore

```

This line of code finds the type within the model, the property within the type, and provides the new instance of our option converter to it. In this entity, a `None` here indicates that the member uses the group’s default e-mail format; `Some` would indicate that they’ve specified which format they prefer.

That’s all there is to it! Define the converter once, and plug it in to all the optional fields; now we have nullable fields translated to options by EF Core. [“Magic unicorn,”](https://twitter.com/efmagicunicorns) indeed!

_(Credits: Many thanks to Jiří Činčura for the [excellent value conversion blog post](https://www.tabsoverspaces.com/233708-using-value-converter-for-custom-encryption-of-field-on-entity-framework-core-2-1) and Tomas Petricek for his [Stack Overflow answer on converting quotation expressions to Linq expressions](https://stackoverflow.com/a/23146624).)_