表达式中的EF Core 3 x.Contains(),其中x是ICollection

时间:2019-09-29 15:58:31

标签: entity-framework-core ef-core-2.1 ef-core-3.0

我已经设置了以下数据层:

public class Repository : IRepository {

    private readonly MyDbContext _dbContext;

        public List<Meter> Search(Expression<Func<Meter,bool>> criteria)
            IQueryable<Meter> results = _dbContext.Meters;
            return results.Where(criteria).ToList();
        }
    }
}

... from a client class:

IRepository _repository;

public void ClientMethod () {

    ICollection<int> ids = new List<int>() {1, 2, 3);
    var results = _repository.Search(c=> ids.Contains(c.Id)); // This throws exception

}

这导致异常:

  

表达式where(源​​:DbSet,谓词:(m)=>   (未处理的参数:__ ids_0)。包含(m.Id))'不能为   翻译。以一种可以翻译的形式重写查询,   或通过插入呼叫明确切换到客户评估   AsEnumerable(),AsAsyncEnumerable(),ToList()或ToListAsync()

但是如果我将集合引用更改为IEnumerable或List,它将起作用:

public void ClientMethod () {

    // This works
    List<int> ids = new List<int>() {1, 2, 3);
    var results = _repository.Search(c=> ids.Contains(c.Id)); 

    // This works
    IEnumerable<int> ids = new List<int>() {1, 2, 3);
    var results = _repository.Search(c=> ids.Contains(c.Id)); 
}

为什么对ICollection不起作用,对IEnumerable和List不起作用?我的许多客户端方法都将ICollection作为参数。

我使用的是EF Core 3.0,但我认为我在2.1中也遇到了同样的问题,因为它没有在客户端评估它而抛出异常。

3 个答案:

答案 0 :(得分:6)

这是3.1中修复的已知错误。由于查询管道重写后的所有回归,3.0几乎不可用。

我建议在github上关注ef core的问题跟踪器。

答案 1 :(得分:4)

从2.2迁移到EF Core 3.0时,我遇到了同样的问题。我已经配置了ef,以便在客户端评估时抛出错误,并且运行正常。因此,我确定这是3.0版中的新问题,是他们重写linq引擎时引入的。

将其投射到IEnumerable或List上也对我有用,谢谢您的提示!

答案 2 :(得分:2)

当您转换为 IEnumerable() 或 List() 时,EFCore 会强制进行客户端评估,这就是它起作用的原因。 (但以性能为代价)

  • “在 3.0 版之前,Entity Framework Core 支持在查询中的任何位置进行客户端评估”Reference
  • 3.0 之前的 EFCore 版本还允许您在混合服务器和客户端评估时添加警告。
  • 然后 EF 更改了策略,不允许您混合使用服务器和客户端评估,因此不会发生意外的性能问题。不过,它比那要复杂一些,所以这里有一个指向 EFCore 3.1 breaking changes 的链接 *所有其他版本也可以在此处以及左侧菜单导航中找到,包括 3.0。