【问题标题】:Finding common items is evaluated locally查找共同项目在本地进行评估
【发布时间】:2019-11-06 03:42:54
【问题描述】:

使用 Entity Framework Core 2.2 我有以下查询:

IQueryable<User> users = _context.Users.AsNoTracking();

User user = await users
  .Include(x => x.UserSkills)
  .ThenInclude(x => x.Skill)
  .FirstOrDefaultAsync(x => x.Id == 1);

var userSkills = user.UserSkills.ToList();

IQueryable<Lesson> lessons = _context.Lessons.AsNoTracking();

var test = lessons
  .Where(x => x.IsEnabled)
  .Where(x => x.LessonSkills.All(y => userSkills.Any(z => y.SkillId == z.SkillId))) 
  .ToList();

我正在寻找包含所有课程技能的用户技能。

当我运行此查询时,我收到以下错误:

Exception thrown: 'System.InvalidOperationException' in System.Private.CoreLib.dll: 
'Error generated for warning 'Microsoft.EntityFrameworkCore.Query.QueryClientEvaluationWarning: 
The LINQ expression 'where ([y].SkillId == [z].SkillId)' could not be translated and will be evaluated locally.'.

如何改变查询来解决这个问题?

更新

我需要用一个额外的选项来扩展这个查询 (y.SkillLevelId &lt;= z.SkillLevelId):

var test = lessons
  .Where(x => x.IsEnabled)
  .Where(x => x.LessonSkills.All(y => userSkills.Any(z => 
     y.SkillId == z.SkillId 
     && 
     y.SkillLevelId <= z.SkillLevelId))) 
  .ToList();

【问题讨论】:

  • 没有。错误“无法翻译并将在本地评估”是每次 Linq 查询无法转换为 SQL 时发出的一般错误。您发布的问题与我的问题不同。错误可能相同,但导致错误的原因不同。

标签: c# entity-framework-core entity-framework-core-2.2


【解决方案1】:

userSkills 是内存中的集合,根据我目前使用 EF6 和 EF Core 的经验,我可以说唯一可靠的具有内存中集合的可翻译构造是基本类型内存中集合的 Enumerable.Contains 方法。

所以下面解决的问题是问题。

首先(应该在查询表达式树之外):

var userSkillIds = user.UserSkills.Select(x => x.SkillId);

然后代替

.Where(x => x.LessonSkills.All(y => userSkills.Any(z => y.SkillId == z.SkillId)))

使用等价的(但可翻译的):

.Where(x => x.LessonSkills.All(y => userSkillIds.Contains(y.SkillId)))

更新:如果你不能使用Contains,在 EF Core 开始支持它之前你有的选项是 (1) EntityFrameworkCore.MemoryJoin 包(我个人没有测试过,但是这个想法很有趣),(2)使用Expression类手动构建基于Or的谓词(很难并且适用于小内存集合)和(3)用真正的IQueryable&lt;&gt;替换内存集合,例如

var userSkills = users
    .Where(x => x.Id == 1)
    .SelectMany(x => x.UserSkills);

并使用原始查询。

【讨论】:

  • 我正在使用 var userSkills = user.UserSkills.ToList(); 将 userSkills 作为内存集合作为尝试解决此问题的原因...我也可以在查询中使用 user.UserSkills 但我也遇到了异常。
  • 我知道你正在收集 UserSkill 对象的内存。这就是问题所在,因为使用它的查询构造不会转换为 SQL。仅选择 ID 并使用 Contains 有效。建议的解决方案有什么问题,您尝试过吗?因为我在发布之前做过并且它对我有用(EF Core 2.2.6)。
  • 对不起,由于我的信息不足,您的回答有问题。如果您检查我刚刚添加的更新,我还需要比较另一个属性:SkillLevel。所以包含不起作用......我最初没有发布这个,因为我想简化问题并且不期望这个遗漏会影响答案。对不起。
  • @MiguelMoura 我明白了。不幸的是,这是非常重要的细节,因为除了 Contains 之外的任何内容都不适用于内存集合。
猜你喜欢
  • 2016-09-18
  • 1970-01-01
  • 1970-01-01
  • 2021-12-22
  • 2017-12-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-11-28
相关资源
最近更新 更多