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 lambda 表达式?
帮助我使用实体框架从 SQL 转换为 linq 嵌套 lambda 表达式