我正在尝试从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())。包含(__ 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))'无法翻译,将会 在当地评估。
答案 0 :(得分:6)
这是因为.ToLower()
和.Contains()
是字符串类中的函数,并且不能由linq提供程序转换为SQL。
所有查询(除非明确指定)都将遵循数据库排序规则,如果它是CI
,则它是Case Insensitive,您不需要.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核心2.0中添加的。对于1.1我不认为有任何方法可以做到这一点。我建议直接跳过EF并编写普通的旧SQL。