LINQ无法翻译。调用“AsEnumerable”、“AsAsyncEnumerable”、“ToList”或“ToListAsync”

问题描述 投票:0回答:1

如何将发送给我进行过滤的列表与我数据库中的列表进行比较?

我的候选实体中有一个名为 CandidateLanguage 的列表。

我从外部得到一个名为 LanguageSkills 的列表来进行过滤。然后,当我获取候选人时,我想进行比较,但出现错误。

我的代码:

var entities = _context.Candidates
    .Include(p => p.CandidateLanguages)
    .Where(m => m.CandidateLanguages
        .Any(l => languageSkills
            .Any(c =>
                c.LanguageId == l.LanguageId &&
                c.Writing <= l.Writing &&
                c.Reading <= l.Reading &&
                c.Speaking <= l.Speaking
            )
        )
    )
    .AsNoTracking();

我收到的错误:

无法翻译。以可翻译的形式重写查询,或者通过插入对“AsEnumerable”、“AsAsyncEnumerable”、“ToList”或“ToListAsync”的调用来显式切换到客户端评估

linq asp.net-core asp.net-web-api entity-framework-core
1个回答
0
投票

正如评论中提到的,EF 无法像过滤器中那样翻译要使用的对象列表(语言技能)。您只能使用简单类型的集合。需要在内存中完成与内存中对象的更复杂的比较。

我们可以根据请求的语言 ID 进行初始过滤:

var languageIds = languageSkills.Select(x => x.LanguageId).Distinct().ToList();

var entities = _context.Candidates
    .Include(p => p.CandidateLanguages)
    .Where(m => m.CandidateLanguages
        .Any(l => laungageIds.Contains(l.LanguageId)))
    .AsNoTracking()
    .ToList();

entities = entities
    .Where(l => languageSkills.Any(c =>
            c.LanguageId == l.LanguageId &&
            c.Writing <= l.Writing &&
            c.Reading <= l.Reading &&
            c.Speaking <= l.Speaking))
    .ToList();

第一个查询针对 SQL 运行并检索所选语言的所有候选语言。从那里我们在内存中过滤它以精确匹配。这种方法的警告是,这可能最终会加载大量数据。

如果您要处理大量要筛选的候选人并且技能标准数量相对合理,则更完整的方法是使用动态表达式生成器根据条件构建

Where
表达式。这将用于从您的语言技能列表中组成 (AND-AND-AND) OR (AND-AND-AND) OR (AND-AND-AND) ... 表达式。这可以使用
PredicateBuilder
来完成,或者在循环中手动编写表达式,或者使用 DynamicWhere Nuget 包之类的东西。

© www.soinside.com 2019 - 2024. All rights reserved.