Entity Framework 3.0 包含无法像在 EF Core 2.2 中那样在 SQL 中进行翻译
Entity Framework 3.0 Contains cannot be translated in SQL as it was in EF Core 2.2
我正在尝试将 Web API 从 .NET Core 2.2 迁移到 .NET Core 3.0,我偶然发现了以下内容:
public Dictionary<int, Tag> GetTagMap(IList<int> tagIds = null)
{
var tags = context.Tag.AsNoTracking();
if (tagIds != null)
tags = tags.Where(t => tagIds.Contains(t.TagId));
return tags
.ToList() // explicit client evaluation in 3.0
.ToDictionary(t => t.TagId, t => t);
}
这用于生成类似于此的 SQL 语句:
SELECT TagId, Name FROM Tag WHERE TagId IN (1, 2, 3)
对于正确索引的列和少量 IN
值非常有效。
现在我收到以下错误提示 List<>.Contains
翻译不再受支持:
System.InvalidOperationException: 'The LINQ expression 'Where(
source: DbSet, predicate: (t) => (Unhandled parameter:
__tagIds_0).Contains(t.TagId))' 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(). See
Client vs. Server Evaluation - EF Core for more information.'
这表明 LINQ queries are no longer evaluated on the client 重大更改,但 AFAIK Contains
未在客户端上进行评估。
我明白发生了什么,为什么我的代码没有按预期运行(服务器端评估),以及为什么显式客户端评估实际上是一件好事:
IList<T>.Contains
实际上是在客户端计算的,但是List<T>.Contains
是在服务器端计算的。只需将 IList
替换为 List 即可使代码在没有显式客户端评估的情况下工作:
public Dictionary<int, Tag> GetTagMap(List<int> tagIds = null)
{
var tags = context.Tag.AsNoTracking();
if (tagIds != null)
tags = tags.Where(t => tagIds.Contains(t.TagId));
return tags
.ToList() // explicit client evaluation in 3.0
.ToDictionary(t => t.TagId, t => t);
}
这是一个 3.0 错误,由 #17342: Contains on generic IList/HashSet/ImmutableHashSet will throw exception 跟踪。
已在 3.1 中修复。解决方法(如果您等不及)是强制使用 Enumerable.Contains
,例如
t => tagIds.AsEnumerable().Contains(t.TagId)
或者改变变量的类型。
我正在尝试将 Web API 从 .NET Core 2.2 迁移到 .NET Core 3.0,我偶然发现了以下内容:
public Dictionary<int, Tag> GetTagMap(IList<int> tagIds = null)
{
var tags = context.Tag.AsNoTracking();
if (tagIds != null)
tags = tags.Where(t => tagIds.Contains(t.TagId));
return tags
.ToList() // explicit client evaluation in 3.0
.ToDictionary(t => t.TagId, t => t);
}
这用于生成类似于此的 SQL 语句:
SELECT TagId, Name FROM Tag WHERE TagId IN (1, 2, 3)
对于正确索引的列和少量 IN
值非常有效。
现在我收到以下错误提示 List<>.Contains
翻译不再受支持:
System.InvalidOperationException: 'The LINQ expression 'Where( source: DbSet, predicate: (t) => (Unhandled parameter: __tagIds_0).Contains(t.TagId))' 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(). See Client vs. Server Evaluation - EF Core for more information.'
这表明 LINQ queries are no longer evaluated on the client 重大更改,但 AFAIK Contains
未在客户端上进行评估。
我明白发生了什么,为什么我的代码没有按预期运行(服务器端评估),以及为什么显式客户端评估实际上是一件好事:
IList<T>.Contains
实际上是在客户端计算的,但是List<T>.Contains
是在服务器端计算的。只需将 IList
替换为 List 即可使代码在没有显式客户端评估的情况下工作:
public Dictionary<int, Tag> GetTagMap(List<int> tagIds = null)
{
var tags = context.Tag.AsNoTracking();
if (tagIds != null)
tags = tags.Where(t => tagIds.Contains(t.TagId));
return tags
.ToList() // explicit client evaluation in 3.0
.ToDictionary(t => t.TagId, t => t);
}
这是一个 3.0 错误,由 #17342: Contains on generic IList/HashSet/ImmutableHashSet will throw exception 跟踪。
已在 3.1 中修复。解决方法(如果您等不及)是强制使用 Enumerable.Contains
,例如
t => tagIds.AsEnumerable().Contains(t.TagId)
或者改变变量的类型。