EF Core 3 x.Contains() 在 x 是 ICollection 的表达式中
EF Core 3 x.Contains() in expression where x is ICollection
我有以下数据层设置:
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
}
这导致异常:
expression Where(source: DbSet, predicate: (m) =>
(Unhandled parameter: __ids_0).Contains(m.Id))' could not be
translated. Either rewrite the query in a form that can be translated,
or switch to client evaluation explicitly by inserting a call to
either AsEnumerable(), AsAsyncEnumerable(), ToList(), or 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 中遇到了同样的问题,它只是没有抛出,因为它是在客户端上评估的。
从 2.2 迁移到 EF Core 3.0 时,我 运行 遇到了同样的问题。我之前已经将 ef 配置为在客户端评估时抛出错误,并且工作正常。所以我确定这是 3.0 的一个新问题,是在他们重写 linq 引擎时引入的。
将其转换为 IEnumerable 或 List 也适用于我,感谢您的提示!
这是 3.1 中修复的已知错误。由于查询管道重写后的所有回归,3.0 几乎无法使用。
我建议关注 github 上的 ef 核心问题跟踪器。
当您转换为 IEnumerable() 或 List() 时,EFCore 会强制进行客户端评估,这就是它起作用的原因。 (但以性能成本工作)
- “在 3.0 版之前,Entity Framework 核心支持查询中任何位置的客户端评估”Reference
- 3.0 之前的 EFCore 版本还允许您在混合服务器和客户端评估时添加警告。
- 然后 EF 更改了政策,不允许您混合使用服务器和客户端评估,因此不会发生意外的性能问题。不过比那个复杂一点,所以这里是 link 到 EFCore 3.1 breaking changes *所有其他版本也可以在左侧菜单导航中找到,包括 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
}
这导致异常:
expression Where(source: DbSet, predicate: (m) => (Unhandled parameter: __ids_0).Contains(m.Id))' could not be translated. Either rewrite the query in a form that can be translated, or switch to client evaluation explicitly by inserting a call to either AsEnumerable(), AsAsyncEnumerable(), ToList(), or 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 中遇到了同样的问题,它只是没有抛出,因为它是在客户端上评估的。
从 2.2 迁移到 EF Core 3.0 时,我 运行 遇到了同样的问题。我之前已经将 ef 配置为在客户端评估时抛出错误,并且工作正常。所以我确定这是 3.0 的一个新问题,是在他们重写 linq 引擎时引入的。
将其转换为 IEnumerable 或 List 也适用于我,感谢您的提示!
这是 3.1 中修复的已知错误。由于查询管道重写后的所有回归,3.0 几乎无法使用。
我建议关注 github 上的 ef 核心问题跟踪器。
当您转换为 IEnumerable() 或 List() 时,EFCore 会强制进行客户端评估,这就是它起作用的原因。 (但以性能成本工作)
- “在 3.0 版之前,Entity Framework 核心支持查询中任何位置的客户端评估”Reference
- 3.0 之前的 EFCore 版本还允许您在混合服务器和客户端评估时添加警告。
- 然后 EF 更改了政策,不允许您混合使用服务器和客户端评估,因此不会发生意外的性能问题。不过比那个复杂一点,所以这里是 link 到 EFCore 3.1 breaking changes *所有其他版本也可以在左侧菜单导航中找到,包括 3.0.