EFCore.FSharp 10.0.0

Edit this page

Many to many relationships

To configure a many to many relationship directly on a type we need to use recursive types.

open System.Linq
open Microsoft.EntityFrameworkCore
open EntityFrameworkCore.FSharp.Extensions

// Use ResizeArray to avoid Unhandled exception. System.NotSupportedException: Collection was of a fixed size.
[<CLIMutable>]
type Post =
    { PostId : int
      Title : string
      Content : string
      Tags : Tag ResizeArray } 
and [<CLIMutable>] Tag =
    { TagId : string
      Posts : Post ResizeArray }

type MyContext () =
  inherit DbContext()
    
  [<DefaultValue>]
  val mutable posts : DbSet<Post>
  member this.Posts with get() = this.posts and set v = this.posts <- v
  
  [<DefaultValue>]
  val mutable tags : DbSet<Tag>
  member this.Tags with get() = this.tags and set v = this.tags <- v
  
  override _.OnModelCreating builder =
      builder.RegisterOptionTypes() // enables option values for all entities

  override __.OnConfiguring(options: DbContextOptionsBuilder) : unit =
      options.UseSqlite("Data Source=blogging.db") |> ignore

let ctx = new MyContext()

let tag = { TagId = "Sunset"; Posts = [] |> ResizeArray }
let post =
    { PostId = 100
      Title = "title"
      Content = "Content"
      Tags = [ tag ] |> ResizeArray }

ctx.Posts.Add post |> ignore
ctx.SaveChanges() |> ignore

let posts = ctx.Posts.Include(fun p -> p.Tags).ToList() |> Seq.toList // from c# to f# list

A limitation is that the types have to be declared in the same file.

namespace System
namespace System.Linq
namespace Microsoft
Multiple items
type CLIMutableAttribute = inherit Attribute new: unit -> CLIMutableAttribute

--------------------
new: unit -> CLIMutableAttribute
type Post = { PostId: int Title: string Content: string Tags: ResizeArray<Tag> }
Post.PostId: int
Multiple items
val int: value: 'T -> int (requires member op_Explicit)

--------------------
type int = int32

--------------------
type int<'Measure> = int
Post.Title: string
Multiple items
val string: value: 'T -> string

--------------------
type string = System.String
Post.Content: string
Post.Tags: ResizeArray<Tag>
type Tag = { TagId: string Posts: ResizeArray<Post> }
type ResizeArray<'T> = System.Collections.Generic.List<'T>
Tag.TagId: string
Tag.Posts: ResizeArray<Post>
Multiple items
type MyContext = new: unit -> MyContext val mutable posts: obj val mutable tags: obj override OnConfiguring: options: 'a -> unit override OnModelCreating: builder: 'a -> 'b member Posts: 'a member Tags: 'a

--------------------
new: unit -> MyContext
Multiple items
type DefaultValueAttribute = inherit Attribute new: unit -> DefaultValueAttribute + 1 overload member Check: bool

--------------------
new: unit -> DefaultValueAttribute
new: check: bool -> DefaultValueAttribute
MyContext.posts: obj
val set: elements: seq<'T> -> Set<'T> (requires comparison)
MyContext.tags: obj
type unit = Unit
val ignore: value: 'T -> unit
val ctx: MyContext
val tag: Tag
val post: Post
property MyContext.Posts: 'a with get, set
val posts: obj list
property MyContext.Posts: 'a array with get, set
module Seq from Microsoft.FSharp.Collections
val toList: source: seq<'T> -> 'T list