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