为EF7中的谓词使用参数时,为什么不能使用ToListAsync()?

时间:2015-10-24 10:39:54

标签: c# asp.net-core entity-framework-core

我目前正在为我的ASP.VNext应用程序实现repository pattern。我希望这些方法是异步和可过滤的。所以我设计了以下接口方法:

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

并希望像这样实现它(使用私有DbContext实例ctx):

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

但是,我只能在对谓词进行硬编码时使用FirstOrDefaultAsync()

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

传递谓词时,我只得到没有async选项的FirstOrDefault(),所以为了使我的方法异步,我必须写

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;
}

我有两个问题:

  1. 为什么在传递谓词时无法访问FirstOrDefaultAsync()方法?

  2. 使用await Task.Run(synchronousMethod)的解决方案是否与调用FirstOrDefaultAsync()的行为相同?

1 个答案:

答案 0 :(得分:1)

FirstOrDefaultAsync被定义为IQueryable<T>的扩展方法。

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

ctx.MyEntities.Where(predicate)会返回IEnumerable<MyEntity>,因为您正在调用Enumerable.Where扩展方法,而不是Queryable.Where方法。

要使其有效,请将predicateFunc<MyEntity, bool>更改为Expression<Func<MyEntity, bool>>。这意味着predicate不再只是一个提供所需结果的函数,而是一个对该函数的描述,然后实体框架可以转换为SQL。

不,在任务中使用Func<MyEntity, bool>不会有相同的行为。这将从数据库服务器加载行而不进行任何过滤,并在数据库客户端评估每个行,直到找到匹配项。这会增加很多开销。