Last active
September 13, 2024 11:44
-
-
Save isaacabraham/42a9f708da31cdb3e67727d7bc377b2a to your computer and use it in GitHub Desktop.
EF Core 8 and F#
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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