EF Core by default does not know anything about the way of F# deals with nullable values which is the Option type.
This project has a way to enable query for columns defined as an option, first you need to call .UseFSharpTypes() on the
context configuration builder
open EntityFrameworkCore.FSharp.Extensions
[<CLIMutable>]
type Blog = {
[<Key>]
Id : Guid
Title : string
Content : string option
}
type MyContext () =
inherit DbContext()
[<DefaultValue>]
val mutable private _blogs : DbSet<Blog>
member this.Blogs with get() = this._blogs and set v = this._blogs <- v
override _.OnModelCreating builder =
builder.RegisterOptionTypes() // enables option values for all entities
override _.OnConfiguring(options: DbContextOptionsBuilder) : unit =
options.UseSqlite("Data Source=dbName.db")
.UseFSharpTypes()
|> ignore
Note that the .UseFSharpTypes() will exist independent of the database, the UseSqlite is just for the example.
If you are using an SQL server with UseSqlServer or UsePostgres for Postgres, or any other database it will exist.
With that, you will be able to query your entity by an optional column.
Querying entities with Some content
let queryWhereSome (ctx: MyContext) =
// Querying entities with `Some` content
let blogs =
query {
for blog in ctx.Blogs do
where blog.Content.IsSome
select blog
}
// or using Linq extensions
let blog =
ctx.Blogs.Where(fun x -> x.Content.IsSome)
()
Querying entities with None content
let queryWhereNone (ctx: MyContext) =
let blogs =
query {
for blog in ctx.Blogs do
where blog.Content.IsNone
select blog
}
// or using Linq extensions
let blog =
ctx.Blogs.Where(fun x -> x.Content.IsNone)
()
Querying optional values by value
let queryWhereValue (ctx: MyContext) =
let blogs =
query {
for blog in ctx.Blogs do
where (blog.Content.Value = "Some text")
select blog
}
// or using Linq extensions
let blog =
ctx.Blogs.Where(fun x -> x.Content.Value = "Some text")
()
Multiple items
type CLIMutableAttribute =
inherit Attribute
new: unit -> CLIMutableAttribute
--------------------
new: unit -> CLIMutableAttribute
type Blog =
{
Id: Guid
Title: string
Content: string option
}
Multiple items
type KeyAttribute =
inherit Attribute
new: unit -> unit
<summary>Denotes one or more properties that uniquely identify an entity.</summary>
--------------------
KeyAttribute() : KeyAttribute
Blog.Id: Guid
Multiple items
[<Struct>]
type Guid =
new: b: byte array -> unit + 6 overloads
member CompareTo: value: Guid -> int + 1 overload
member Equals: g: Guid -> bool + 1 overload
member GetHashCode: unit -> int
member ToByteArray: unit -> byte array + 1 overload
member ToString: unit -> string + 2 overloads
member TryFormat: utf8Destination: Span<byte> * bytesWritten: byref<int> * ?format: ReadOnlySpan<char> -> bool + 1 overload
member TryWriteBytes: destination: Span<byte> -> bool + 1 overload
static member (<) : left: Guid * right: Guid -> bool
static member (<=) : left: Guid * right: Guid -> bool
...
<summary>Represents a globally unique identifier (GUID).</summary>
--------------------
Guid ()
Guid(b: byte array) : Guid
Guid(b: ReadOnlySpan<byte>) : Guid
Guid(g: string) : Guid
Guid(b: ReadOnlySpan<byte>, bigEndian: bool) : Guid
Guid(a: int, b: int16, c: int16, d: byte array) : Guid
Guid(a: int, b: int16, c: int16, d: byte, e: byte, f: byte, g: byte, h: byte, i: byte, j: byte, k: byte) : Guid
Guid(a: uint32, b: uint16, c: uint16, d: byte, e: byte, f: byte, g: byte, h: byte, i: byte, j: byte, k: byte) : Guid
Blog.Title: string
Multiple items
val string: value: 'T -> string
--------------------
type string = String
Blog.Content: string option
type 'T option = Option<'T>
Multiple items
type MyContext =
new: unit -> MyContext
override OnConfiguring: options: 'a -> unit
override OnModelCreating: builder: 'a -> 'b
member Blogs: IQueryable<Blog>
--------------------
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._blogs: obj
val set: elements: seq<'T> -> Set<'T> (requires comparison)
type unit = Unit
val ignore: value: 'T -> unit
val queryWhereSome: ctx: MyContext -> unit
val ctx: MyContext
val blogs: IQueryable<Blog>
val query: Linq.QueryBuilder
val blog: Blog
property MyContext.Blogs: IQueryable<Blog> with get, set
custom operation: where (bool)
Calls Linq.QueryBuilder.Where
property Option.IsSome: bool with get
custom operation: select ('Result)
Calls Linq.QueryBuilder.Select
val blog: IQueryable<Blog>
(extension) Collections.Generic.IEnumerable.Where<'TSource>(predicate: Func<'TSource,bool>) : Collections.Generic.IEnumerable<'TSource>
(extension) Collections.Generic.IEnumerable.Where<'TSource>(predicate: Func<'TSource,int,bool>) : Collections.Generic.IEnumerable<'TSource>
(extension) IQueryable.Where<'TSource>(predicate: Expressions.Expression<Func<'TSource,bool>>) : IQueryable<'TSource>
(extension) IQueryable.Where<'TSource>(predicate: Expressions.Expression<Func<'TSource,int,bool>>) : IQueryable<'TSource>
val x: Blog
val queryWhereNone: ctx: MyContext -> unit
property Option.IsNone: bool with get
val queryWhereValue: ctx: MyContext -> unit
property Option.Value: string with get