UPDATE: The code described below is now available as a NuGet package.
The 2.1 release of Entity Framework Core brought the ability to do 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 that you don’t have to write, such as storing
enums as strings. To use a value converter, you provide a new instance of it and attach it to a property in your model’s
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 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
nullable columns as well? As it turns out, yes!
Here is the code for the value converter.
module Conversion =
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, 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:
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,” indeed!
(Credits: Many thanks to Jiří Činčura for the excellent value conversion blog post and Tomas Petricek for his Stack Overflow answer on converting quotation expressions to Linq expressions.)