Skip to content

Instantly share code, notes, and snippets.

@isaacabraham
Last active September 13, 2024 11:44
Show Gist options
  • Save isaacabraham/42a9f708da31cdb3e67727d7bc377b2a to your computer and use it in GitHub Desktop.
Save isaacabraham/42a9f708da31cdb3e67727d7bc377b2a to your computer and use it in GitHub Desktop.
EF Core 8 and F#
#r "nuget:Microsoft.EntityFrameworkCore.SqlServer, 8.0.8"
open Microsoft.EntityFrameworkCore
open System
open System.Linq
// Our domain model with a custom wrapped ID type
type Id<'T> =
| Id of Guid
member this.Value =
match this with
| Id id -> id
type TodoId = interface end
type Todo = {
Id: Id<TodoId>
Title: string
CreatedDate: DateTime
}
type TodoContext(connectionString: string) =
inherit DbContext()
override _.OnConfiguring options =
options.UseSqlServer connectionString |> ignore
override _.OnModelCreating modelBuilder =
modelBuilder.Entity(fun builder ->
// Not using [<CliMutable>] so must explicitly map all fields.
builder.HasKey "Id" |> ignore
builder.Property(_.Id).HasConversion(_.Value, Id) |> ignore // Converting between Guid and TodoId
builder.Property _.Title |> ignore
builder.Property _.CreatedDate |> ignore
)
|> ignore
member val Todo = base.Set<Todo>() with get
let connectionString =
"Data Source=localhost,1433;Database=TodoDb;User=sa;Password=yourStrong(!)Password; TrustServerCertificate=True;"
let ctx = new TodoContext(connectionString)
// Simple query using LINQ extension methods
let fsharpTodos =
ctx.Todo
.Where(fun todo -> todo.Title.Contains "Functional Programming")
.ToArray()
// Simple query using F# query expression syntax
let fsharpTodosExpr =
query {
for todo in ctx.Todo do
where (todo.Title.Contains "Functional Programming")
select todo
}
|> Seq.toArray
// Simple query using hand-written raw SQL
let fsharpTodosRaw =
ctx.Todo.FromSqlRaw "SELECT Id, Title, CreatedDate FROM dbo.Todo WHERE Title LIKE '%Functional Programming%' "
|> Seq.toArray
// Projection - just get all titles
let allTitles = ctx.Todo.Select _.Title |> Seq.toArray
// Update that fails - entity already exists in the context
let updated = {
fsharpTodos[0] with
Title = fsharpTodos[0].Title + "Updated"
}
ctx.Todo.Update updated
// Update that works - requires a new "clean" context
let secondCtx = new TodoContext(connectionString)
secondCtx.Todo.Update updated
secondCtx.SaveChanges()
// "Remote" update - no data is loaded into memory
ctx.Todo
.Where(fun todo -> todo.Title.Contains "Functional Programming")
.ExecuteUpdate(fun calls -> calls.SetProperty(_.Title, (fun todo -> todo.Title + "UPDATED")))
// Inserting a new entity
let newTodo = {
Id = Id(Guid.NewGuid())
Title = "Test 2"
CreatedDate = DateTime.UtcNow
}
ctx.Add newTodo
ctx.SaveChanges()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment