Announcing EFCore.FSharp
Tags: fsharp, efcore, dotnet, sql
Published: 2021-03-21 15:58:19

---
title: Announcing EFCore.FSharp
published: true
date: 2021-03-21 15:05:49 UTC
tags: FSharp,EFCore,dotnet,sql
canonical_url: https://SimonReynolds.ie/announcing-efcore-fsharp/
---

 ![Announcing EFCore.FSharp](https://images.unsplash.com/photo-1483736762161-1d107f3c78e1?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=1080&fit=max&ixid=eyJhcHBfaWQiOjExNzczfQ)

Today marks the first alpha release of F# support for Entity Framework Core, allowing for direct usage of EF Core from your F# projects with support for EF Core 5.0.3  
It contains support for migrations and reverse-engineering, allowing you to map tables to F# records and take advantage of F# idioms such as `option` to represent nullable columns. At the moment though, this does not work for primary or foreign keys, just plain columns ([GitHub issue](https://github.com/efcore/EFCore.FSharp/issues/29)).

To take it for a test drive, grab the NuGet package from [https://www.nuget.org/packages/EntityFrameworkCore.FSharp](https://www.nuget.org/packages/EntityFrameworkCore.FSharp)  
Bear in mind that it is an alpha release so please log any issues on the [GitHub repo](https://github.com/efcore/EFCore.FSharp).

Currently it has support for relatively simple schemas, it does not support many-types-per-table relationships yet but that is [on the to-do list](https://github.com/efcore/EFCore.FSharp/issues/21).

Although it does support `option` columns it does not yet support types such as discriminated unions.

### Installation

All the usual ways of grabbing a NuGet package...

`Install-Package EntityFramworkCore.FSharp`  
`dotnet add package EntityFramworkCore.FSharp`  
`paket install EntityFramworkCore.FSharp`

### Usage

When it is installed, you will need to register it for `dotnet ef` to pick it up. Simply add the following code to your project. It will be detected at compile time, no need to call it from a  `Startup` class

<!--kg-card-begin: markdown-->
```fsharp
module DesignTimeServices

open Microsoft.Extensions.DependencyInjection
open Microsoft.EntityFrameworkCore.Design
open EntityFrameworkCore.FSharp

type DesignTimeServices() =
    interface IDesignTimeServices with 
        member __.ConfigureDesignTimeServices(serviceCollection: IServiceCollection) = 
            let fSharpServices = EFCoreFSharpServices.Default
            fSharpServices.ConfigureDesignTimeServices serviceCollection
            ()
```
<!--kg-card-end: markdown-->
###    
Migrations

Code first databases are supported, a working example of creating a basic MVC application in F# with user authentication is available at [https://github.com/simon-reynolds/EFCore.FSharp.MvcAuth](https://github.com/simon-reynolds/EFCore.FSharp.MvcAuth)

One thing to remember is that record types have to have the `[<CliMutable>]` attribute specified so that they can be created correctly by Entity Framework.

After running `dotnet ef migration add` you will need to add the created files to your your project. The migration files are generated sequentially so you can add a single glob reference to your fsproj file to add them all at once

<!--kg-card-begin: markdown-->
```xml
<Compile Include="Migrations/*.fs" />
```
<!--kg-card-end: markdown-->

There is an [issue](https://github.com/efcore/EFCore.FSharp/issues/20) to track this to try find an automated solution. As always, any help or suggestions are welcome.

### Scaffolding

When scaffolding a model from an existing database, we can specify how we want the generated code to be created in our `DesignTimeServices` type above.

We can create types as either record types or classes similar to how they behave in C#

For instance, given a blog post type with an Id, Title and Content, it can generated as either example below.

<!--kg-card-begin: markdown-->
```fsharp
// Record type
type BlogPost = {
    Id : int
    Title: string
    Content: string
}

// Class type
type BlogPost() =

    [<DefaultValue>] val mutable private _Id : int
    member this.Id with get() = this._Id and set v = this._Id <- v

    [<DefaultValue>] val mutable private _Title : string
    member this.Title with get() = this._Title and set v = this._Title <- v

    [<DefaultValue>] val mutable private _Content : string
    member this.Content with get() = this._Content and set v = this._Content <- v
```
<!--kg-card-end: markdown-->

Similarly, optional columns can either be rendered as `Nullable<'a>` or as `'a option`. The default configuration will create record types with nullable columns specified as `option` types.

These are done by defining our scaffold options and passing them into the `DesignTimeServices`, e.g.

<!--kg-card-begin: markdown-->
```fsharp
module DesignTimeServices =

    open Microsoft.Extensions.DependencyInjection
    open Microsoft.EntityFrameworkCore.Design
    open EntityFrameworkCore.FSharp

    type DesignTimeServices() =
        interface IDesignTimeServices with
            member __.ConfigureDesignTimeServices(serviceCollection: IServiceCollection) =
                
                // The default behaviour can be specified by calling
                let fSharpServices = EFCoreFSharpServices.Default

                // Or we can define a ScaffoldOptions use that instead
                let scaffoldOptions =
                    ScaffoldOptions (
                        ScaffoldTypesAs = ScaffoldTypesAs.ClassType,
                        ScaffoldNullableColumnsAs = ScaffoldNullableColumnsAs.NullableTypes)

                let fSharpServices = EFCoreFSharpServices.WithScaffoldOptions scaffoldOptions

                fSharpServices.ConfigureDesignTimeServices serviceCollection
                ()
```
<!--kg-card-end: markdown-->

More details can be found in our project documentation [here](https://efcore.github.io/EFCore.FSharp//How_Tos/Scaffold_As_Types.html).

### Option types

It has basic support for `option` types, including an `OptionConverter` for mapping nullable columns to options. When building a code first database simply include the following at the end of `OnModelCreating`

```fsharp
type MyContext (options) = 
    inherit DbContext (options)

    override this.OnModelCreating mb =
        (* Define entities here *)
        
        modelBuilder.RegisterOptionTypes()
```

### Other issues

I'm sure there are. Please report any issues you discover and help us improve F# support for Entity Framework Core!