Saturday, November 9, 2013

Entity Framework 6, CountAsync and PredicateBuilder

My previous subject was about the ToListAsync() method used with the PredicateBuilder from LinqKit which was not working due to the AsExpandable() call and the not implemented IDbAsyncEnumerable interface...

After the modification that you can find in the previous post, I have tried to call the CountAsync() method and a similar exception occured:
"System.InvalidOperationException : The provider for the source IQueryable doesn't implement IDbAsyncQueryProvider. Only providers that implement IDbAsyncQueryProvider can be used for Entity Framework asynchronous operations." 
Another modification on LinqKit is needed for this new case: we just need to take my previous modification and use this implementation of ExpandableQueryProvider class with the following code:


   1:  public class ExpandableQueryProvider<T> : IDbAsyncQueryProvider
   2:  {
   3:      readonly ExpandableQuery<T> _query;
   4:      
   5:      internal ExpandableQueryProvider(ExpandableQuery<T> query)
   6:      {
   7:          _query = query;
   8:      }
   9:   
  10:      IQueryable<TElement> IQueryProvider.CreateQuery<TElement>(Expression expression)
  11:      {
  12:          return new ExpandableQuery<TElement>(_query.InnerQuery.Provider.CreateQuery<TElement>(expression.Expand()));
  13:      }
  14:   
  15:      IQueryable IQueryProvider.CreateQuery(Expression expression)
  16:      {
  17:          return _query.InnerQuery.Provider.CreateQuery(expression.Expand());
  18:      }
  19:      
  20:      TResult IQueryProvider.Execute<TResult>(Expression expression)
  21:      {
  22:          return _query.InnerQuery.Provider.Execute<TResult>(expression.Expand());
  23:      }
  24:      
  25:      object IQueryProvider.Execute(Expression expression)
  26:      {
  27:          return _query.InnerQuery.Provider.Execute(expression.Expand());
  28:      }
  29:      
  30:      public Task<object> ExecuteAsync(Expression expression, CancellationToken cancellationToken)
  31:      {
  32:          return Task.FromResult(_query.InnerQuery.Provider.Execute(expression.Expand()));
  33:      }
  34:   
  35:      public Task<TResult> ExecuteAsync<TResult>(Expression expression, CancellationToken cancellationToken)
  36:      {
  37:          return Task.FromResult(_query.InnerQuery.Provider.Execute<TResult>(expression.Expand()));
  38:      }
  39:  }

With that new stuff, CountAsync() will work as usual even after a call to AsExpandable()!

1 comment:

  1. Hi Denis. Fantastic what you've done. I got this problem when I was trying to use FirstOrDefaultAsync. I've changed for this code, however, I've found a problem: It's losing the Includes before the Where. For example

    db.Users.AsExpandable().Include("Client").Where(predicate).FirstOrDefaultAsync();

    The Include, load the refence of User.Client, when we want to get some details about the client (User.Client.CliName).

    Have you got this problem too?

    ReplyDelete

Note: Only a member of this blog may post a comment.