F# Record Types With Entity Framework Code-First

I was spinning up a data layer in a new FSharp project and I thought I would take EF Code-first out for a test drive.  I have use EF-CF in a couple of C# projects so I am familiar with the premise (and the promise) of code-first.  The FSharp project uses record types, nested record types, and choice types exclusively so I I thought of attaching each of these types for code first in turn.  The first article that I ran across was this one, which seemed like a good start.  I went ahead a created a family record type like so, matching the example verbatim except I swapped out the class implementation with a record type:

 

1 #r "../packages/EntityFramework.6.1.2/lib/net45/EntityFramework.dll" 2 3 open System.Collections.Generic 4 open System.ComponentModel.DataAnnotations 5 open System.Data.Entity 6 7 type Family = {Id:int; LastName:string; IsRegistered:bool} 8 9 type CLFamily() = 10 inherit DbContext() 11 [<DefaultValue>] 12 val mutable m_families: DbSet<Family> 13 member public this.Families with get() = this.m_families 14 and set v = this.m_families <- v 15 16 let db = new CLFamily() 17 let family = {Id=0;LastName="New Family"; IsRegistered=true} 18 db.Families.Add(family) |> ignore 19 db.SaveChanges() |> ignore 20

But I ran into this:

 image

image

So I added the Key attribute to the Record type

image

So I hit up stack overflow with this question and sure enough, I forgot to add a reference to that assembly.  Once I added it, then it compiled.  I then ran the script and I got the following error message:

1 <add name="CLFamily" 2 connectionString="Server=.;Database=FamilyDomain;Trusted_Connection=True;" 3 providerName="System.Data.SqlClient"/> 4

 

image

Ugh!  It was still hitting the default connection string.    I went ahead and adjusted my script to account for the connection string and I swapped out the backing values with CLIMutable:

1 #r "../packages/EntityFramework.6.1.2/lib/net45/EntityFramework.dll" 2 #r "C:/Program Files (x86)/Reference Assemblies/Microsoft/Framework/.NETFramework/v4.5.1/System.ComponentModel.DataAnnotations.dll" 3 4 open System.Collections.Generic 5 open System.ComponentModel.DataAnnotations 6 open System.Data.Entity 7 8 [<CLIMutable>] 9 type Family = {[<Key>]Id:int; LastName:string; IsRegistered:bool;} 10 11 12 type FamilyContext() = 13 inherit DbContext() 14 [<DefaultValue>] val mutable families: DbSet<Family> 15 member this.Families with get() = this.families and set f = this.families <- f 16 17 let context = new FamilyContext() 18 let connectionString = "Server=.;Database=FamilyDomain;Trusted_Connection=True;" 19 context.Database.Connection.ConnectionString <- connectionString 20 let family = {Id=0; LastName="Test"; IsRegistered=true} 21 context.Families.Add(family) |> ignore 22 context.SaveChanges() |> ignore

And sure enough, the table is created in the database and the record is persisted:

image image

And the cool thing is that even though this is a record type, the Id does adjust to the identity value given by the database.

With that out of the way, I went to tackle nested types.  I added a Child class and a list of children to the family class. 

1 [<CLIMutable>] 2 type Child = {[<Key>]Id:int; FamilyId: int; FirstName:string; Gender:string; Grade:int} 3 4 [<CLIMutable>] 5 type Family = {[<Key>]Id:int; LastName:string; IsRegistered:bool; Children:Child list} 6 7 type FamilyContext() = 8 inherit DbContext() 9 [<DefaultValue>] val mutable families: DbSet<Family> 10 member this.Families with get() = this.families and set f = this.families <- f 11 [<DefaultValue>] val mutable children: DbSet<Child> 12 member this.Chidlren with get() = this.children and set c = this.children <- c 13 14 let context = new FamilyContext() 15 let connectionString = "Server=.;Database=FamilyDomain;Trusted_Connection=True;" 16 context.Database.Connection.ConnectionString <- connectionString 17 let children = [{Id=0; FamilyId=0; FirstName="Test"; Gender="Male"; Grade=5}] 18 let family = {Id=0; LastName="Test"; IsRegistered=true; Children=children } 19 context.Families.Add(family) |> ignore 20 context.SaveChanges() |> ignore

Everything compiled and  ran, but the Children table was not added to the database –> though the new record was added.

image image image

Going back to stack overflow, it looks like EF Code First will not auto-update the schema unless you add some more glue code.  Ugh.  At that point, I might as well give up on code-first if all it brings is not having to write sql scripts…

One Response to F# Record Types With Entity Framework Code-First

  1. Pingback: F# Weekly #2, 2015 | Sergey Tihon's Blog

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: