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


137

我已经读到使用ToUpper和ToLower执行不区分大小写的字符串比较是不明智的,但是在LINQ-to-SQL方面我看不到其他选择。LINQ-to-SQL会忽略String.Compare的ignoreCase和CompareOptions参数(如果使用区分大小写的数据库,则即使要求进行不区分大小写的比较,也会得到区分大小写的比较)。ToLower或ToUpper是这里的最佳选择吗?这个比那个好吗?我以为我在某处读到ToUpper更好,但是我不知道这在这里是否适用。(我正在做很多代码审查,每个人都在使用ToLower。)

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

这将转换为仅将row.Name与“ test”进行比较的SQL查询,并且在区分大小写的数据库上不会返回“ Test”和“ TEST”。


1
谢谢!今天,这真的救了我的屁股。注:它与其他LINQ扩展太喜欢LINQQuery.Contains("VaLuE", StringComparer.CurrentCultureIgnoreCase)LINQQuery.Except(new string[]{"A VaLUE","AnOTher VaLUE"}, StringComparer.CurrentCultureIgnoreCase)。哇!
格雷格·布雷

有趣的是,我只是读到与该来源进行比较,ToUpper更好:msdn.microsoft.com/en-us/library/dd465121
malckier 2013年

Answers:


110

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

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

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

注意,但是,这并不能工作在这种情况下!因此,我们被困在ToUpperor上ToLower

请注意顺序 IgnoreCase以使其安全。但是,您使用的区分大小写(不区分大小写)的检查的确切类型取决于您的用途。但通常在排序时使用“等于”进行相等性检查和“比较”,然后为该工作选择正确的StringComparison。

迈克尔·卡普兰(Michael Kaplan,文化和角色处理方面的公认权威)在ToUpper与ToLower上有相关文章:

他说:“ String.ToUpper – 使用ToUpper而不是ToLower,并指定InvariantCulture来选择OS外壳规则


1
看来这不适用于SQL Server:print upper('GroßeStraße')返回GROßESTRAßE– BlueMonkMN
2009年

1
此外,您提供的示例代码与我提供的代码存在相同的问题,但在MS SQL 2005数据库上通过LINQ-to-SQL运行时,它们区分大小写。
BlueMonkMN,2009年

2
我同意。对不起,我不清楚。正如您在原始问题中指出的那样,我提供的示例代码不适用于Linq2Sql。我只是在重申您的开始方式是一个不错的方法-如果它只能在这种情况下起作用。是的,另一个Mike Kaplan消息框是SQL Server的字符处理无处不在。如果您需要不区分大小写并且无法通过其他任何方式获取,我建议(不清楚)将数据存储为大写,然后将其查询为大写。
安德鲁·阿诺特

3
好吧,如果您有区分大小写的数据库,并且以大小写混合的形式进行存储,并且以大写形式进行搜索,则不会获得匹配项。如果您在搜索中同时对数据和查询都进行了大写,那么您将为每个查询转换要搜索的所有文本,这并不是很有效。
安德鲁·阿诺特

1
@BlueMonkMN,确定要粘贴正确的代码段吗?很难相信MSSQL Server更喜欢Red而不是Black。
greenoldman

75

System.Data.Linq.SqlClient.SqlMethods.Like(row.Name, "test") 在查询中使用 过。

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


3
哈!几年来一直在使用linq 2 sql,但是直到现在为止还没有看到SqlMethods,谢谢!
CarlHörberg2010年

3
辉煌!不过,可以使用更多细节。这是Like的预期用途之一吗?是否有可能导致假阳性结果的输入?还是假阴性结果?这个方法的文档缺乏,哪来的文档描述类似方法的操作?
任务

2
我认为这仅取决于SQL Server如何比较字符串,这可能是可以在某个地方配置的。
Andrew Davey 2010年

11
System.Data.Linq.SqlClient.SqlMethods.Like(row.Name,“ test”)与row.Name.Contains(“ test”)相同。正如安德鲁所说,这取决于sql server的排序规则。因此,Like(或包含)并不总是执行不区分大小写的比较。
doekman 2010年

3
请注意,这会使代码太过随意SqlClient
贾德2015年

5

我使用Lambda表达式进行了尝试,并且有效。

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


18
这是因为您使用的是List<>,这意味着比较是在内存中(C#代码)进行的,而不是在数据库中执行比较的IQueryable(或ObjectQuery)。
drzaus

1
@drzaus说了什么。考虑到上下文是linq2sql,而不是常规linq,这个答案是完全错误的。
rsenna

0

如果将不区分大小写的字符串传递给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"

如您所见,string参数将在SQL中进行比较,这意味着事情应该按照您期望的方式工作。


我不明白你在说什么。1)字符串本身在.NET中不能区分大小写或区分大小写,因此我不能传递“不区分大小写的字符串”。2)LINQ查询基本上是一个lambda表达式,这就是我传递两个字符串的方式,因此这对我来说没有任何意义。
BlueMonkMN

3
我想对CASE-SENSITIVE数据库执行CASE-INSENSITIVE比较。
BlueMonkMN,2009年

您正在使用哪种区分大小写的数据库?
安德鲁·黑尔

同样,LINQ查询也不是lambda表达式。LINQ查询由几个部分组成(最著名的是查询运算符和lambda表达式)。
安德鲁·黑尔

作为BlueMonkMN的注释,此答案没有意义。
阿尔夫(Alf)

0

若要对SQL查询执行区分大小写的Linq,请通过使用以下方法之一来指定服务器数据类型,以将“字符串”字段声明为区分大小写;

varchar(4000) COLLATE SQL_Latin1_General_CP1_CS_AS 

要么

nvarchar(Max) COLLATE SQL_Latin1_General_CP1_CS_AS

注意:以上归类类型中的“ CS”表示“区分大小写”。

使用Visual Studio DBML Designer查看属性时,可以在“服务器数据类型”字段中输入该字段。

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


这就是问题。通常,我使用的字段区分大小写(化学式CO [一氧化碳]与Co [钴]不同)。但是,在特定情况下(搜索),我希望co匹配Co和CO。用其他“服务器数据类型”定义其他属性是不合法的(linq to sql仅允许每个sql列使用一个属性)。所以仍然没有去。
doekman 2010年

另外,如果进行单元测试,则此方法可能无法与数据模拟兼容。最好在接受的答案中使用linq / lambda方法。
德里克(Derrick)2012年

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

1
将此文本转换成什么SQL文本?在SQL环境中将其区分大小写的原因是什么?
BlueMonkMN

0

以下两阶段方法对我有效(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);
}

1
该代码有缺陷,如果文本与搜索文本开始(应> = 0)
Flatliner DOA

@FlatlinerDOA实际上应该是!= -1因为IndexOf “如果找不到字符或字符串,则返回-1”
drzaus16年

0

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

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

解决此问题的方法是先删除空间,然后转换大小写,然后再选择

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

在这种情况下请注意

customname是与数据库值匹配的值

UsersTBs是类

标题是“数据库”列


-1

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

使用String.Equals很可能(我猜是)从SQL Server中带回所有行,然后在.NET中进行比较,因为它是无法转换为T-SQL的.NET表达式。

换句话说,使用表达式将增加您的数据访问权限,并失去使用索引的能力。它会在小桌子上工作,您不会注意到其中的区别。在大桌子上,它的性能可能非常差。

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

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


2
这是不正确的(它不会导致将行返回给客户端)。我使用了String.Equals,它不起作用的原因是因为它被转换为TSQL字符串比较,其行为取决于数据库或服务器的排序规则。我确实考虑了如何将我编写的每个LINQ to SQL表达式转换为TSQL。达到我想要的方式是使用ToUpper强制生成的TSQL使用UPPER。然后,所有转换和比较逻辑仍然在TSQL中完成,因此您不会损失太多性能。
BlueMonkMN 2013年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.