Using QuerySpec FetachAsync with F# AsyncBuilder

Posts   
 
    
NathanFox
User
Posts: 30
Joined: 05-Mar-2011
# Posted on: 17-Mar-2023 12:48:03   

I'm trying to execute a Query Spec query using FetchQueryAsync in an F# asynchronous computation expression.

For example:

let getNewItemRequestEntity (aggregateId: string) =
  async {
    use da = new DataAccessAdapter()
    let qf = QueryFactory()
    let q = 
      qf.NewItemRequest
        .Where(NewItemRequestFields.AggregateId.Equal(Guid.Parse(aggregateId)))
    return!
      da.FetchQueryAsync<NewItemRequestEntity>(q, CancellationToken.None)
      |> Async.AwaitTask
  }

This code fails to compile with the following error: The type 'AsyncBuilder' is not compatible with the type 'IEntityFieldCore'

I've searched the internet, but I can't find why this might be.

Is this something known? Or maybe there is a work around? I can use the non-async methods to execute the queries, but I'd prefer to use the async operations.

I'm using LLBLGen Pro 5.9.0

Thank you for any help.

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39613
Joined: 17-Aug-2003
# Posted on: 17-Mar-2023 13:21:35   

To be honest, we have no experience with F# and are not familiar with 'AsyncBuilder' nor this error and what the cause might be, sorry flushed From what I can understand with similar issues on the internet with type x not compatible with type y, it might be it's related to return values or a cast that's not possible, but looking at your code, not sure what should change (as we have no / not much experience with F#). (to me it looks ok-ish, the method you're calling returns a Task<T> which should be appended with an Async.AwaitTask, but for the rest... no idea why this error is thrown.).

As the method you're calling returns an IEntityCollection2, it might be the type generator for F# doesn't know how to evaluate this. You can perhaps work around this by first instantiate the entity collection, and pass that to the FetchQueryAsync method.

Do other async methods also fail?

Frans Bouma | Lead developer LLBLGen Pro
NathanFox
User
Posts: 30
Joined: 05-Mar-2011
# Posted on: 17-Mar-2023 14:24:22   

Hmm, I tried to get more specific in casting as follows:

let getNewItemRequestEntity2 (aggregateId: string) =
  async {
    use da = new DataAccessAdapter()
    let qf = QueryFactory()
    let collection = new EntityCollection<NewItemRequestEntity>()
    let q: EntityQuery<NewItemRequestEntity> = 
      qf.NewItemRequest
        .Where(NewItemRequestFields.AggregateId.Equal(Guid.Parse(aggregateId)))
    return!
      da.FetchQueryAsync<NewItemRequestEntity, EntityCollection<NewItemRequestEntity>>(q, collection, CancellationToken.None)
      |> Async.AwaitTask
  }

Unfortunately, I get the same compilation error. For now I can use the non-async versions and investigate further in the future. Thank you for taking a look at it.

NathanFox
User
Posts: 30
Joined: 05-Mar-2011
# Posted on: 17-Mar-2023 14:26:52   

Interesting, I tried using F# query syntax as well with the LINQ provider...

let getNewItemRequestEntity3 (aggregateId: string) =
  async {
    use da = new DataAccessAdapter()
    let metaData = LinqMetaData(da)
    let q = 
      query {
        for r in metaData.NewItemRequest do
        where (r.AggregateId = Guid.Parse(aggregateId))
        select r
      }
    return! 
      q.ToListAsync()
      |> Async.AwaitTask
  }

Still get the same compilation error.

NathanFox
User
Posts: 30
Joined: 05-Mar-2011
# Posted on: 17-Mar-2023 14:31:17   

To further follow up, I've used the same asynchronous model interacting the Microsoft's CosmosDB client, and it works fine. I wish the error message was more informative. I checked with a co-worker and we used the async builder heavily with Microsoft's System.Net.Http.HttpClient successfully.

NathanFox
User
Posts: 30
Joined: 05-Mar-2011
# Posted on: 17-Mar-2023 15:21:23   

I guess it just doesn't like entities :-)

let getNewItemRequestEntity2 () =
  async {
    return! Task.FromResult(new NewItemRequestEntity())
  }

Produces the same compilation error.

NathanFox
User
Posts: 30
Joined: 05-Mar-2011
# Posted on: 17-Mar-2023 15:57:27   

Interesting. Just want to follow up in case someone else hits this issue.

If I remove the reference to QuerySpec as in...

open SD.LLBLGen.Pro.QuerySpec
open SD.LLBLGen.Pro.QuerySpec.Adapter

Then the compilation error goes away for the LINQ meta data query and the Task.FromResult example. So, it must be something in QuerySpec that extends a class or interface in some way it doesn't like.

For example the following now compiles and runs:

module Test

open SD.LLBLGen.Pro.LinqSupportClasses
open vendordb.DatabaseSpecific
open vendordb.Linq
open System

let getNewItemRequestEntity3 (aggregateId: string) =
  async {
    use da = new DataAccessAdapter()
    let metaData = LinqMetaData(da)
    let q = 
      query {
        for r in metaData.NewItemRequest do
        where (r.AggregateId = Guid.Parse(aggregateId))
        select r
      }
    return! 
      q.ToListAsync()
      |> Async.AwaitTask
  }

If I add:

open SD.LLBLGen.Pro.QuerySpec

Then compilation fails.

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39613
Joined: 17-Aug-2003
# Posted on: 18-Mar-2023 09:21:19   

Thanks for the info. Strange! The namespace is rather big so I don't know exactly what it could be. QuerySpec is based on extension methods like Linq is too, however contrary to what Linq does, it's not an API that's based on an immutable state. Not sure if that's the issue, as it works with the synchronous methods, as you said.

I have honestly no idea what it might be caused by, so I've to guess what it can be but it can be anything. I do recall F# generating type libraries behind the scenes on the used types, at first I thought it might go wrong somewhere with the interfaces, but why would it work in synchronous code but not in async code?

Frans Bouma | Lead developer LLBLGen Pro