In an answer to my another question I was told to use QueryExtensions to achieve async computations with F# and Entity Framework, and I'm using that advice successfully.
For example, I have the following function:
let headAsync query =
query
|> QueryableExtensions.FirstAsync
|> Async.AwaitTask
that can be used this way:
async {
let! entity =
query {
for e in context.MyEntities do
sortBy e.Id
} |> headAsync
return entity
}
It'd be nice though to use my new function as a query expression. I've written this:
type QueryBuilderEx() =
inherit Linq.QueryBuilder()
[<CustomOperation("headAsync")>]
member __.HeadAsync<'T, 'Q when 'Q :> System.Linq.IQueryable<'T>> (source: Linq.QuerySource<'T, 'Q>) : Async<'T> =
let queryable = source.Source :?> 'Q
queryable.FirstOrDefaultAsync() |> Async.AwaitTask
let query2 = QueryBuilderEx()
And trying to use it like this:
async {
let! entity =
query2 {
for e in context.MyEntities do
sortBy e.Id
headAsync
}
return entity
}
This code compiles fine, but throws the following exception at runtime:
System.NotSupportedException: This is not a valid query expression. The method 'Microsoft.FSharp.Control.FSharpAsync`1[Entities.MyEntity] HeadAsync[MyEntity,IQueryable`1](Microsoft.FSharp.Linq.QuerySource`2[Entities.MyEntity,System.Linq.IQueryable`1[Entities.MyEntity]])' was used in a query but is not recognized by the F#-to-LINQ query translator. Check the specification of permitted queries and consider moving some of the operations out of the query expression
So, is the extension of the standard LINQ translator possible, or I should stick to my previous headAsync implementation in form of ordinary function without messing with QueryBuilder?
You may get more mileage out of intercepting the queries and rewriting on the fly, you might be able to turn the expressions into something the EF translator will work with. See https://github.com/ImaginaryDevelopment/IInterceptQueryables
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With