LINQ 表达式未转换为 SQL

Posted

技术标签:

【中文标题】LINQ 表达式未转换为 SQL【英文标题】:LINQ expression is not being translated to SQL 【发布时间】:2018-04-07 17:11:57 【问题描述】:

我正在尝试从 LINQ 实现已编译的 SQL 查询,它将检查 query 是否是数据库中三列中任意一列的子字符串(不区分大小写)。

我使用的是 .NET Core 1.1

我想出的查询如下:

users.Select(u => new
  
    User = u,
    query = u.FirstName.ToLower() + u.LastName.ToLower() + u.Email.ToLower()
  ).Where(x => x.query.Contains(query))

但是在查看调试信息时,我收到了以下警告:

无法翻译 LINQ 表达式 '(([u].FirstName.ToLower() + [u].LastName.ToLower()) + [u].Email.ToLower()).Contains(__query_0)'并将在本地进行评估。

我尝试的第二个查询:

 users.Where(x => u.FirstName.ToLower().Contains(query) || u.LastName.ToLower().Contains(query) || u.Email.ToLower().Contains(query))

但它给了我完全相同的警告。

为什么会这样? 我正在寻找类似的东西:

SELECT * FROM USERS WHERE FirstName LIKE query OR LastName LIKE query OR Email LIKE query

更新

我又做了一个实验:

    users.Where(u =>
    u.FirstName.Contains(query) ||
    u.LastName.Contains(query) ||
    u.Email.Contains(query));

这也导致了

LINQ 表达式 '(([u].FirstName.Contains(__query_0) OrElse [u].LastName.Contains(__query_1)) OrElse [u].Email.Contains(__query_2))' 无法翻译,将被 当地评价。

【问题讨论】:

如果您的数据库排序规则是xxx_CI,则不需要.ToLower()SELECT CONVERT (varchar, SERVERPROPERTY('collation')); 验证。 感谢您的提示,我有SQL_Latin1_General_CP1_CI_AS。但是我认为(也许我错了)当我的查询未编译为 SQL 时,它将区分大小写。 我不确定您所说的“未编译”是什么意思?如果您对 Linq2Objects 运行相同的查询而不是 yes,它的行为会有所不同。 (区分大小写) 请注意,您的查询方法存在缺陷(您可能关心也可能不关心)。对于名为 John Nyman 的用户,您将创建一个类似 johnnymanjohn.nyman@company.com 的查询。如果用户正在寻找“Johnny”,他将在 John Nyman 上获得点击,即使“Johnny”没有出现在名字、姓氏或电子邮件中。另请注意,如果交换串联顺序,您会得到不同的结果:将姓氏放在首位 (nymanjohnjohn.nyman@company.com) 突然不会产生“Johnny”的命中。 @Flater 是真的!谢谢,我很在乎。 【参考方案1】:

这是因为.ToLower().Contains()是字符串类中的函数,不能被linq提供者翻译成SQL。 所有查询(除非明确指定)都将遵循数据库排序规则,如果它是 CI,则它不区分大小写,您不需要 .ToLower()。 至于.Contains(),则需要使用实体函数Like

users.Where(u =>
    EF.Functions.Like(u.FirstName, "%" + query + "%") ||
    EF.Functions.Like(u.LastName, "%" + query + "%") ||
    EF.Functions.Like(u.Email, "%" + query + "%"));

但是这似乎是在 EF core 2.0 中添加的。对于 1.1,我认为没有任何方法可以做到这一点。我建议跳过 EF 并直接编写普通的旧 SQL。

【讨论】:

即使在本地评估部分查询,这是否成立? 不,linq2Object 部分将区分大小写。我建议您使用.AsEnumerable() 指定查询的某些部分应该是本地的。 这个我明白。然而,这并没有回答我原来的问题:为什么上面的 LINQ 查询没有被翻译成 SQL。 这是因为 linq 提供程序无法翻译 .ToLower(),因为它是字符串类中的一个函数。 我认为它已添加到 Core 2.0 中。与 EF 6 相比,EF Core 缺少很多功能。有关详细信息,请参阅 blogs.msmvps.com/ricardoperes/2016/09/05/…。

以上是关于LINQ 表达式未转换为 SQL的主要内容,如果未能解决你的问题,请参考以下文章

将 SQL 转换为 LINQ 方法表达式

如何将带有内连接的 sql 查询转换为 linq lambda 表达式?

帮助我使用实体框架从 SQL 转换为 linq 嵌套 lambda 表达式

将 Oracle SQL 转换为 LLBLGEN LINQ 表达式 C#

将 lambda 表达式转换为 ORM 中的 SQL?

将 sql 转换为 LINQ C#