我的加入 .NetCore 3.1 抛出了一个关于 NavigationExpandingExpressionVisitor 的异常,那是什么?

7 R*_*eds 6 c# entity-framework-core ef-core-3.1

我有一个 .NetCore 3.1 项目。我知道从 EF Core 2 到 3 发生了重大变化,但寻找解决方案却让我发现了一些毫无意义的地方。

以下适用于 .NetCore 2.2。

我有一个从其他查询生成的用户名列表。我现在想在我们的人事数据库中找到这些用户名,目的是返回每个用户名的关联电子邮件地址。一个人可以选择使用公司电子邮件地址或提供不同的地址。如果该person.EmailAddress字段为空,则我需要的地址是附加了公司域的用户名。

private static List<string> GetEmailAddrsFromBp(PersonnelContext personnelContext, IEnumerable<string> userNames) {
    try {

        var personEmail = (
            from person in personnelContext.Persons
            join userName in userNames
                on person.userName.Trim().ToLower() equals userName.Trim().ToLower()
            where person.ActualEndDate == null
            select person.EmailAddress.Trim().Equals("")
                ? person.userName.Trim().ToLower() + "@myCompany.com"
                : person.EmailAddress.Trim().ToLower()
        ).Distinct().OrderBy(a => a).ToList();

        return personEmail;
    } catch (Exception e) {
        throw new Exception("GetEmailAddrsFromBp: " + e.Message);
    }
}
Run Code Online (Sandbox Code Playgroud)

在 3.1 我得到异常:

Processing of the LINQ expression 'DbSet<Persons>
    .Join(
        outer: __p_0, 
        inner: person => person.userName.Trim().ToLower(), 
        outerKeySelector: userName => userName.Trim().ToLower(), 
        innerKeySelector: (person, userName) => new { 
            person = person, 
            userName = userName
         })' by 'NavigationExpandingExpressionVisitor' failed. This may indicate either a bug or a limitation in EF Core. See https://go.microsoft.com/fwlink/?linkid=2101433 for more detailed information.
Run Code Online (Sandbox Code Playgroud)

我不明白这个错误。转到建议的 Microsoft 站点没有帮助。其他谷歌搜索已被证明无济于事。到底是怎么回事?您现在如何进行“简单”连接?

Iva*_*oev 4

我不明白这个错误。

当然,错误消息对用户来说并不友好。唯一相关的部分是

这可能表明 EF Core 中存在错误或限制。

可以安全地将其解读为“这EF Core 中的错误或限制”。

到底是怎么回事?现在如何进行“简单”连接?

可以执行“简单”连接,但不能连接到内存集合。事实上,内存集合的连接从未得到真正的支持。只是 EF Core 1.x / 2.x 使用所谓的客户端评估来处理它无法翻译的内容。但是隐式客户端评估已在 3.0 中删除,现在您应该找到可翻译的构造,或者通过 LINQ to Objects(或System.Linq.Async)显式切换到客户端评估。

由于专门针对连接切换到客户端评估效率不高,因此最好找到/使用可翻译的查询构造。如果你使用非等值或多键连接,你基本上没有选择。但是对于单键等连接,所有 EF / EF Core 版本都支持一个构造,它会Enumerable.Contains转换为 SQL IN (val1, val2, ..., valN)

因此,针对您具体情况的解决方案将是这样的:

userNames = userNames.Select(userName => userName.Trim().ToLower()).Distinct();

var personEmail = (
    from person in personnelContext.Persons
    where userNames.Contains(person.userName.Trim().ToLower())
    // the rest of the query unchanged...
Run Code Online (Sandbox Code Playgroud)