Net core EF 3.1中LINQ字符串比较不再起作用

9

我有以下类:

public class Employee
{
    public string Name {get; set;}
    ...
}

在 EF Core 2.1 中,使用 LINQ 查询

Employee GetEmployeeByName(string name) {
  return Context.Employee.Where ( w =>String.Compare(w.Name, name, true) == 0).FirstOrDefault();
}

将其转换为Net Core EF 3.1后,出现错误。

LINQ表达式无法翻译。请将查询重写为可翻译的形式,或通过插入对AsEnumerable()AsAsyncEnumerable()ToList()ToListAsync()之一的调用来显式切换到客户端评估。

我必须更改查询为

Employee GetEmployeeByName(string name) {
  return Context.Employee.Where ( w =>w.Name.ToLower() == name.ToLower()).FirstOrDefault();
}

有更好的方法吗?


你使用的是哪个数据库? - Caius Jard
微软 SQL Server。 - user3097695
1
我从barett的回答中得出结论——只有在客户端使用C#进行字符串操作时,才会出现大小写敏感的情况。对于传递给数据库的简单查询,例如 .Where(x => x.Name == "Smith"),大小写敏感取决于数据库,而SQL Server默认情况下通常不区分大小写。 - Caius Jard
4个回答

9
如果您需要进行大小写不敏感的字符串比较,建议使用EF.Functions扩展,它可以转换为正确的SQL语句。
您的示例将变成这样(使用Like):
using Microsoft.EntityFrameworkCore;

Employee GetEmployeeByName(string name) {
  return Context.Employee.Where(w => EF.Functions.Like(w.Name, name)).FirstOrDefault();
}

这意味着(根据服务器版本的不同)大致相当于
SELECT TOP(1) <<list of fields here>> FROM Employee WHERE Name LIKE(@name)
可用的函数取决于EF Core版本和底层DBMS,但由于您提到了SQL Server,上述内容将起作用,假设您使用了“默认”排序规则。相关:MSSQL Server中的LIKE运算符是否区分大小写?

EF.Functions 可以与除 MsSql 之外的其他 DB 引擎一起使用吗? - Fadhly Permata
1
是的。可用的功能以及其工作方式取决于您安装的提供程序。这在我的答案中有说明。 - Tieson T.
1
不,EF.Functions类适用于多个供应商。根据您使用的内容,您将看到不同的函数。 - Tieson T.
嗯,我明白你的意思。非常抱歉我的英语不好,也许我的上一条评论对你来说不太清楚。非常感谢你的详细解释。 - Fadhly Permata

1

正如@tieson-t所提到的,您可以使用EF.Functions进行Like比较,但根据用例,可能更“适当”的方法是指定比较的排序规则。

与@barrett777建议定义列的默认排序规则不同,有一个名为Collate的EF.Function,您可以在其中指定当前查询要使用的排序规则。

例如,对于SQLite,我使用了

.Where(t => EF.Functions.Collate(t.Name, "NOCASE").Equals(m))

更多排序信息...


0

0

你仍然可以完全做到这一点... 在.NET Core 2.2中实现

Employee GetEmployeeByName(string name) {
    return Context.Employee.Where(w =>String.Compare(w.Name, name, true) == 0).FirstOrDefault();
}

在.NET Core 3.1中,它确实执行了它被告知要做的相同的事情:

Employee GetEmployeeByName(string name) {
    var entityList = Context.Employee.ToList();
    return entityList.Where(w =>String.Compare(w.Name, name, true) == 0).FirstOrDefault();
}

这只是微软让你意识到你必须检索表的所有条目才能进行字符串比较的一种方式... 在 .NET Core 2.2 中就是这样发生的。

来源: https://learn.microsoft.com/en-us/ef/core/what-is-new/ef-core-3.0/breaking-changes#linq-queries-are-no-longer-evaluated-on-the-client


1
这是一种低效的方式,它会将DB-Server中的所有数据加载到App-Server中,然后通过特定的条件过滤结果(并删除不匹配的结果)。您必须保留IQueryable<T>中的行,以确保EF仅加载经过筛选的数据(生成查询)。 - Fadhly Permata
1
当然是这样,这也是微软决定将其视为错误的原因,除非你是有意为之。没有其他方法可以精确地执行所要求的操作,因为“String.Compare”无法转换为SQL查询。 - Nicolas Perego
1
在这种情况下,我同意。但是对于使用 LinqToSql,ToLower 是最好的方法(我认为)。 - Fadhly Permata
1
当然可以,如果不区分大小写的话。 - Nicolas Perego

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接