2

Let's say I have a Projects table in my DB with multiple relationships. Various different queries in the DB layer of my c# code would be interested in joining this table with different others. So I abstracted away the following:

public IQueryable<Project> QueryProject(Project prj)
{
    return Context.Projects.Where(p => p.id == prj.id);
}

... so I can reuse this method in various other scenarios, such as...

_queryService.QueryProject(prj).Include(p => p.Users)

... or

_queryService.QueryProject(prj).Include(p => p.Artefacts)

... etc. At one point, I decide that making action methods asynchronous is a good idea, so I try the following:

await _queryService.QueryProject(prj).Include(p => p.Artefacts).SingleAsync();

However, the moment I try to make any operation using the QueryProject method asynchronous, I get the following error from my unit tests:

The source IQueryable doesn't implement IAsyncEnumerable. Only sources that implement IAsyncEnumerable can be used for Entity Framework asynchronous operations.

So clearly I shouldn't be using IQueryable as a return type for my first QueryProject abstraction. However, I'm struggling to find a viable alternative. I do NOT want any DB retrieval of entities during the execution of QueryProject. I'm also not interested in hacks that simply hide this error without bringing me any benefit. I'm only trying to abstract away repeating code.

Is some type of alternative supported in .NET core 2.1?

P.S. Ivan Stoev raised a valid concern, that the problem could be in my unit tests. Here's my mocking code for reference (using Moq):

mockServices.Setup(x => x.QueryProject(It.IsAny<SomeProjectAbstraction>()))
    .Returns(new List<Project>
    {
        new Project
        {
            Name = ...
        }
    }.AsQueryable());
nikovn
  • 1,900
  • 5
  • 22
  • 28
  • Does the code work when you use code inside QueryProject directly? – Euphoric Aug 13 '18 at 13:20
  • "*I get the following error from my **unit tests**"* Then most likely the issue is not caused by EF Core, but your unit tests mocks or whatever you use there (except a real EF Core `IQueryable`). – Ivan Stoev Aug 13 '18 at 13:27
  • 1
    Thank you @Euphoric and Ivan Stoev - the problem has to do with the way I mock variables. With this observation it was easy to find an already existing answer, so I'd mark my own question as a duplicate (or delete it)... – nikovn Aug 13 '18 at 13:51

1 Answers1

1

IQueryable<T> is a construct that enables you to build up queries before they are handled by the database. There's nothing async about any of that. The part where async gets involved is when you actually send the query to your database and wait for the response (which is what is happening when you use SingleAsync()). At that point, you no longer have an IQueryable<T>, because now it's an actual result set.

Chris Pratt
  • 232,153
  • 36
  • 385
  • 444
  • 1
    This doesn't explain anything about why the OP is getting the error that they're getting or how to correct it. The question demonstrates that they understand that `IQueryable` is used for building a query, not executing it, given that they asked how to do what they're asking without materializing the results of the query. – Servy Aug 13 '18 at 13:29