Using single case union types for entity IDs in F# and making it work with Dapper
Tags: dotnet, fsharp, dapper
Published: 2019-05-12 09:42:39

---
title: Using single case union types for entity IDs in F# and making it work with Dapper
published: true
tags: dotnet,Fsharp,Dapper
canonical_url: http://leruplund.dk/2019/05/12/1055/
cover_image: https://i0.wp.com/leruplund.dk/wp-content/uploads/2019/05/DSC1905-1200x800.jpg?resize=1200%2C800
---

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](https://andrewlock.net/using-strongly-typed-entity-ids-to-avoid-primitive-obsession-part-1/) 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):

```csharp
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](https://fsharpforfunandprofit.com/posts/designing-with-types-single-case-dus/). All it takes is this:

```fsharp
type CarID = CarID of int
```

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

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

id1 = id2 // true
```

As Scott Wlaschin points out on the legendary [F# for fun and profit](https://fsharpforfunandprofit.com/posts/designing-with-types-single-case-dus/) you can use single case union types for anything, not just IDs:

```fsharp
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:

```fsharp
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.

```fsharp
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.

```fsharp
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:

```fsharp
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.