实体框架3.0包含无法像在EF Core 2.2中那样在SQL中进行翻译

我试图将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:'LINQ表达式'Where(   来源:DbSet,谓词:(t)=>(未处理的参数:   __tagIds_0)。包含(t.TagId))'无法翻译。以可以翻译的形式重写查询,或切换到   通过插入对其中任何一个的调用来明确评估客户   AsEnumerable(),AsAsyncEnumerable(),ToList()或ToListAsync()。看到   客户端与服务器评估-EF核心以获取更多信息。'

这表明LINQ queries are no longer evaluated on the client发生了重大变化,但是客户端未评估AFAIK Contains

smithhyj 回答:实体框架3.0包含无法像在EF Core 2.2中那样在SQL中进行翻译

这是一个3.0错误,由#17342: Contains on generic IList/HashSet/ImmutableHashSet will throw exception跟踪。

已在3.1中修复。解决方法(如果您迫不及待)例如是强制使用Enumerable.Contains

t => tagIds.AsEnumerable().Contains(t.TagId)

或更改变量的类型。

,

我了解发生了什么,为什么我的代码表现不如预期(服务器端评估),为什么显式客户端评估实际上是一件好事:

IList<T>.Contains实际上是在客户端上评估的,但是List<T>.Contains是在服务器端上评估的。只需用List替换IList即可使代码正常工作,而无需进行明确的客户评估:

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);
}
本文链接:https://www.f2er.com/3167898.html

大家都在问