Using single case union types for entity IDs in F# and make it work with Dapper

In C# it is a common and popular pattern to use strongly typed entity IDs instead of using integers or the likes for IDs on your entities. Strongly typed entity IDs is a great help when trying to prevent you from mixing an Order ID with an OrderLine ID.

Andrew Lock recently wrote a series on the topic that you should go read now.

A strongly typed entity ID may look something like this (the example used by Andrew Lock):

public readonly struct OrderId : IComparable<OrderId>, IEquatable<OrderId>
{
    public int Value { get; }

    public OrderId(int value)
    {
        Value = value;
    }

    public bool Equals(OrderId other) => this.Value.Equals(other.Value);
    public int CompareTo(OrderId other) => Value.CompareTo(other.Value);

    public override bool Equals(object obj)
    {
        if (ReferenceEquals(null, obj)) return false;
        return obj is OrderId other && Equals(other);
    }

    public override int GetHashCode() => Value.GetHashCode();
    public override string ToString() => Value.ToString();

    public static bool operator ==(OrderId a, OrderId b) => a.CompareTo(b) == 0;
    public static bool operator !=(OrderId a, OrderId b) => !(a == b);
}

That is a lot of code to write for every ID in your domain model and you should create a code snippet in Visual Studio to do it. However, as with many things you get this more or less for free in F# with single case union types. All it takes is this:

type CarID = CarID of int

F# will give to equal operators and the other stuff for free, hence:

let id1 = (CarID 42)
let id2 = (CarID 42)

id1 = id2 // true

As Scott Wlaschin points out on the legendary F# for fun and profit you can use single case union types for anything, not just IDs:

module Domain =
    type CarID = CarID of int
    type CarMake = CarMake of string
    type Model = Model of string

    type Car = {
        CarID: CarID;
        Make: CarMake;
        Year: int;
        Model: Model;
    }

I am not saying this is always a good idea but don’t take it for any more than an example.

What happens if you try to read a Car from a database with Dapper?

Single case union types and Dapper

Dapper uses reflection to create instances of your entity types either by calling the appropriate constructor or by setting properties. For F# record types you cannot set the properties so Dapper tries to call the constructor when querying the database:

use cn = getConnection ()
let cars = cn.Query<Car>("SELECT CarID, Make, Year, Model FROM Car")

This will fail because Dapper tries to find a constructor on OrderLine with the signature (int * string * int * string).

To help Dapper convert from int to CarID, from string to Make and so on you can register a type handler with Dapper. A type handler is a class that inherits SqlMapper.TypeHandler<>. For reading CarID from the database the type handler would look like this.

    type CarIDTypeHandler() =
        inherit SqlMapper.TypeHandler<CarID>()

        override x.SetValue(parameter: IDbDataParameter, value: CarID) =
            ()
        
        override x.Parse(value: obj) = 
            (CarID (Convert.ToInt32(value)))

You register the type handler with Dapper with SqlMapper.AddTypeHandler(typeof<CarID>, new CarIDTypeHandler()). It gets boring very quickly to write type handlers for every single single case union type you come up with (sorry about that strange sentence) and fortunately there is a way to write a generic type handler for single case union types using reflection.

    type SingleCaseUnionTypeHandler<'T>() =
        inherit SqlMapper.TypeHandler<'T>()

        override x.SetValue(parameter: IDbDataParameter, value: 'T) =
            ()
    
        override x.Parse(value: obj) =
            let cases = FSharpType.GetUnionCases(typedefof<'T>)
            FSharpValue.MakeUnion(cases.[0], [| value |]) :?> 'T

The last line makes use of FSharpValue.MakeUnion to create a union. It assumes that the union type 'T has one and only one case when using cases.[0]. I have not found a way to restrict the generic type parameter to unions.

Now you can register the type handler for all single case union types:

SqlMapper.AddTypeHandler(typeof<CarID>, new SingleCaseUnionTypeHandler<CarID>())
SqlMapper.AddTypeHandler(typeof<CarMake>, new SingleCaseUnionTypeHandler<CarMake>())
SqlMapper.AddTypeHandler(typeof<Model>, new SingleCaseUnionTypeHandler<Model>())

Closing

Above we have seen how we can easily use single case union types for type safe handling of entity IDs and other values to prevent using them interchangeably. We have also created a generic Dapper type handler for single case union types.

The generic type handler is only suitable for cases where you do not need extra logic or validation for creating your single union value types and you should also be careful when it comes to performance issues with the reflection in case you need to handle large amounts of instances.

Which is better for teaching? C# or F#

Recently I have had the pleasure of training a couple of colleagues in the wonders of programming. At work we use C# for most of our applications so naturally I started preparing my material in C#.

I did not get very far before it occurred to me: This is going to be a long haul…

Now, my colleagues are smart, really smart, much smarter than me, but they do not have much experience in programming. They have been using SQL, some VBA, and perhaps a bit of R, but none of them have been doing real application development and they know nothing about OO theory.

Unfortunately, you do not get very far with a language such as C# without knowing just a little bit about OO programming.

Let’s start with the compulsory and useless “Hello, world” example:

using System;

namespace ConsoleApp
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Hello, world");
}
}
}

That’s a lot of code just to print out a stupid message on the screen.

“What are all those things for?” my colleague complains and I answer “We’ll get to namespaces, classes, static, void, arrays, and more stuff later”. He’s not happy and continues “Do I really need to write all those curly braces and semicolons?”. And when I tell him yes, and don’t forget that it’s all case sensitive, he breaks down and says “I miss VBA…”.

Of course curly brackets and case sensitivity has nothing to do with OO but I think we can all agree that OO is really, really hard. Heck, I don’t even master it after years of C++ and C#.

I find that it takes a long time for beginners to grasp OO and when they start to see the light they will abuse inheritance and create everything as singletons. And interfaces seem to be impossible to understand even though I do my best with lousy metafors such as cars and DVD playsers.

Usually, beginners actually tend to completely ignore that C# is object oriented and they take a straight forward approach and create a very long Main function.

So, perhaps teaching my colleagues C# is not the right approach. Perhaps I should try teaching them a functional language instead such as F#? Now, I am not saying that functional languages are easy but I do think that you can get really far with F# without knowing advanced stuff such as monads. In F# the “Hello, world” example boils down to

printfn "Hello, world"

Very simple. Not much to talk about.

Besides, there are a couple of important points to consider when bringing F# to the table:

  • My colleagues are all mathematicians and functional languages are perfect for math stuff.
  • F# is a .NET language and will work together with all the C# code in our company.
  • F# can work as a scripting language for makeshift assignments.

I am thinking that it would suffice to teach the basics of F# such as record types, functions, pattern matching, the Seq module, type providers, and perhaps partial application.

What do you think? Would F# be easier to grasp or should I go for the usual C#?