Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Customizing EF F# Query Translator

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?

like image 903
ForNeVeR Avatar asked Jan 20 '26 04:01

ForNeVeR


1 Answers

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

like image 62
Maslow Avatar answered Jan 21 '26 22:01

Maslow