简体   繁体   中英

Why can't I use ToListAsync() when using a parameter for the predicate in EF7?

I'm currently implementing the repository pattern for my ASP.VNext application. I would like the methods to be asynchronous and filterable. So I have devised the following interface method:

Task<TEntity> GetOneAsync(Func<TEntity,bool> predicate);

and would like to implement it like this (with a private DbContext instance ctx ):

public async Task<MyEntity> GetOneAsync(Func<MyEntity,bool> predicate) 
{
    // compiler error
    return await ctx.MyEntities.Where(predicate).FirstOrDefaultAsync();
}

However I can only use FirstOrDefaultAsync() when hardcoding the predicate like this:

return await ctx.MyEntites.Where(e => e.Id == 1).FirstOrDefaultAsync();

When passing the predicate i only get the FirstOrDefault() without the async option, so in order to make my method asynchronous I have to write

public async Task<MyEntity> GetOneAsync(Func<MyEntity,bool> predicate) 
{
    //save to a local variable to prevent calling a disposed DbContext
    var entities = await Task.Run(() => ctx.Contracts.Where(predicate).FirstOrDefault());
    return entities;
}

I have two questions regarding this:

  1. Why is it not possible to access the FirstOrDefaultAsync() method when passing a predicate?

  2. Does my solution using await Task.Run(synchronousMethod) achieve the same behavior as a call to FirstOrDefaultAsync() would?

FirstOrDefaultAsync is defined as an extension method for IQueryable<T> .

ctx.MyEntities.Where(e => e.Id == 1) returns IQueryable<MyEntity> .

ctx.MyEntities.Where(predicate) returns IEnumerable<MyEntity> , because you're calling the Enumerable.Where extension method, not the Queryable.Where one.

To make it work, change predicate from Func<MyEntity, bool> to Expression<Func<MyEntity, bool>> . This means predicate is no longer just a function that gives the result you want, but a description of that function, that Entity Framework can then translate to SQL.

And no, using Func<MyEntity, bool> within a task would not have the same behaviour. That would load rows from the db server without any filtering, and evaluate each and every one at the db client until a match is found. That would add a lot of overhead.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM