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

本文关键字:不能 为什么 ToListAsync 参数 EF7 谓词 | 更新日期: 2023-09-27 18:19:13

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

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();

当传递谓词时,我只得到没有异步选项的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()调用相同的行为?

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

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>不会有相同的行为。这将从db服务器加载行而不进行任何过滤,并在db客户端评估每一行,直到找到匹配。这会增加很多开销。