LINQ-to-SQL 中不区分大小写的字符串比较

我读到过使用 ToUpper 和 ToLower 来执行不区分大小写的字符串比较是不明智的,但是在 LINQ-to-SQL 方面我看不到其他选择。String 的 ignoreCase 和 CompareOptions 参数。LINQ-to-SQL 忽略比较(如果使用区分大小写的数据库,即使请求区分大小写的比较,也会得到区分大小写的比较)。ToLower 或者 ToUpper 是最好的选择吗?一个比另一个好吗?我以为我在哪里读到过 ToUpper 更好,但我不知道这是否适用于这里。(我做了很多代码检查,每个人都在使用 ToLower。)

Dim s = From row In context.Table Where String.Compare(row.Name, "test", StringComparison.InvariantCultureIgnoreCase) = 0

这转换为一个简单地比较行的 SQL 查询。名称为“ TEST”,并且不会在区分大小写的数据库上返回“ TEST”和“ TEST”。

124549 次浏览

如果您将一个不区分大小写的字符串传递给 LINQ-to-SQL,它将被不加修改地传递给 SQL,并且比较将在数据库中进行。如果你想在数据库中进行不区分大小写的字符串比较,你所需要做的就是创建一个 lambda 表达式来进行比较,LINQ-to-SQL 提供程序会将这个表达式转换成一个 SQL 查询,而你的字符串是完整的。

例如这个 LINQ 查询:

from user in Users
where user.Email == "foo@bar.com"
select user

由 LINQ-to-SQL 提供程序转换为以下 SQL:

SELECT [t0].[Email]
FROM [User] AS [t0]
WHERE [t0].[Email] = @p0
-- note that "@p0" is defined as nvarchar(11)
-- and is passed my value of "foo@bar.com"

正如您所看到的,字符串参数将在 SQL 中进行比较,这意味着事情应该按照您预期的方式工作。

正如您所说的,ToUpper 和 ToLower 之间有一些重要的区别,当您试图执行不区分大小写的相等检查时,只有一个是可靠准确的。

理想情况下,执行不区分大小写的相等性检查 就是的最佳方法是:

String.Equals(row.Name, "test", StringComparison.OrdinalIgnoreCase)

注意,无论如何 ,在这种情况下这样做 不是工作! 因此,我们被困在 ToUpperToLower

请注意 普通的IgnoreCase,以确保它的安全性。但是确切地说,您使用的大小写敏感检查的类型取决于您的目的是什么。但通常使用 Equals 进行相等性检查,并在排序时进行比较,然后为作业选择正确的字符串比较。

Michael Kaplan (一个公认的文化和性格处理方面的权威)在 ToUpper vs ToLower 上有相关的帖子:

他说“ String.ToUpper-使用 ToUpper 而不是 ToLower,并指定 InvariantCulture 以获取 OS 大小写规则

我用过 System.Data.Linq.SqlClient.SqlMethods.Like(row.Name, "test") 在我的问题。

这将执行不区分大小写的比较。

要执行区分大小写的 Linq To Sql 查询,可以使用下列方法之一指定服务器数据类型,从而将“ string”字段声明为区分大小写的;

varchar(4000) COLLATE SQL_Latin1_General_CP1_CS_AS

或者

nvarchar(Max) COLLATE SQL_Latin1_General_CP1_CS_AS

注意: 上述排序规则类型中的“ CS”表示“区分大小写”。

在使用 VisualStudioDBML 设计器查看属性时,可以在“ ServerDataType”字段中输入此信息。

有关详细信息,请参阅 http://yourdotnetdesignteam.blogspot.com/2010/06/case-sensitive-linq-to-sql-queries.html

我试过用 Lambda 表达式,结果奏效了。

List<MyList>.Any (x => (String.Equals(x.Name, name, StringComparison.OrdinalIgnoreCase)) && (x.Type == qbType) );

以下两个阶段的方法适合我(VS2010、 ASP.NET MVC3、 SQL Server 2008、 Linq to SQL) :

result = entRepos.FindAllEntities()
.Where(e => e.EntitySearchText.Contains(item));


if (caseSensitive)
{
result = result
.Where(e => e.EntitySearchText.IndexOf(item, System.StringComparison.CurrentCulture) >= 0);
}

请记住,查询是否工作和它是否工作 有效率之间是有区别的!当 LINQ 语句的目标是 SQLServer 时,该语句将转换为 T-SQL,因此需要考虑将生成的 T-SQL。

使用 String。Equals 最有可能(我猜测)从 SQLServer 返回所有行,然后在。NET,因为它是一个。NET 表达式,无法翻译成 T-SQL。

换句话说,使用表达式将增加数据访问,并消除使用索引的能力。它可以在小桌子上使用,你不会注意到它们的不同。在一张大桌子上,它可能表现得非常糟糕。

这是 LINQ 存在的问题之一; 人们不再考虑如何实现他们所写的语句。

在这种情况下,没有一种不使用表达式就可以完成任务的方法,即使在 T-SQL 中也是如此。因此,您可能无法更有效地执行此操作。即使是上面给出的 T-SQL 答案(使用带有排序的变量)也很可能导致索引被忽略,但是如果它是一个大表,那么值得运行语句并查看执行计划,看看是否使用了索引。

where row.name.StartsWith(q, true, System.Globalization.CultureInfo.CurrentCulture)

有时,存储在数据库中的值可能包含空格,因此运行此操作可能会失败

String.Equals(row.Name, "test", StringComparison.OrdinalIgnoreCase)

解决这个问题的方法是先去掉空格,然后转换它的格子,然后选择这样的

 return db.UsersTBs.Where(x => x.title.ToString().ToLower().Replace(" ",string.Empty).Equals(customname.ToLower())).FirstOrDefault();

注意在这种情况下

Customname 是与 Database 值匹配的值

UsersTB 是 class

Title 是 Database 列

使用.NET 内核时,System.Data.Linq.SqlClient.SqlMethod 不可用,请改用此方法

EF.Functions.Like(row.Name, "test")

根据 EF 核心文档,决定不提供一个开箱即用的案例不敏感性比较翻译是根据设计,主要是由于性能方面的考虑,因为数据库索引不会被使用:

.NET 提供了接受 StringComparison枚举的 string.Equals的重载,它允许指定比较的区分大小写和区域性。通过设计,EFCore 避免将这些重载转换为 SQL,并且尝试使用它们将导致异常。一方面,EFCore 不知道应该使用哪种区分大小写或不区分大小写的排序规则。更重要的是 在大多数情况下,应用排序规则会阻止索引的使用,从而严重影响非常基本和常用的。NET 架构

也就是说,从 EF Core 5.0开始,可以指定每个查询的排序规则,这可以用来执行不区分大小写的比较:

Dim s = From row In context.Table
Where EF.Functions.Collate(row.Name, "SQL_Latin1_General_CP1_CI_AS") == "test"

和 C #

var s = context.Table
.Where(row => EF.Functions.Collate(row.Name, "SQL_Latin1_General_CP1_CI_AS") == "test")