Сравнение строк без учета регистра в LINQ-to-SQL


Я читал, что неразумно использовать ToUpper и ToLower для выполнения сравнения строк без учета регистра, но я не вижу альтернативы, когда речь заходит о LINQ-to-SQL. IgnoreCase и CompareOptions аргументы строки.Сравнение игнорируется LINQ-to-SQL (если вы используете базу данных с учетом регистра, вы получаете сравнение с учетом регистра, даже если вы просите сравнение без учета регистра). Является ли ToLower или ToUpper лучшим вариантом здесь? Разве одно лучше другого? Я думал, что где-то читал, что Таппер был лучше, но я не знаю, применимо ли это здесь. (Я делаю много обзоров кода, и все используют ToLower.)

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

это переводится в SQL-запрос, который просто сравнивает row.Name с помощью " test "и не будет возвращать" Test "и" TEST " в базе данных с учетом регистра.

9 128

9 ответов:

Как вы говорите, есть некоторые важные различия между ToUpper и ToLower, и только один из них является достоверно точным, когда вы пытаетесь выполнить проверки равенства без учета регистра.

В идеале, лучший способ сделать проверку равенства без учета регистра-это:

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

Примечание порядковый номерIgnoreCase, чтобы сделать его безопасным для безопасности. Но именно тип чувствительной проверки case (in), которую вы используете, зависит от ваших целей. Но в целом использование равно для равенства проверяет и сравнивает при сортировке, а затем выбрать правильный StringComparison для задания.

Майкл Каплан (признанный авторитет по культуре и обработка символов, таких как этот) имеет соответствующие должности на ToUpper и нижестоящим:

Он говорит "строку.ToUpper – используйте ToUpper, а не ToLower, и укажите InvariantCulture для того, чтобы подобрать правила оболочки ОС"

Я System.Data.Linq.SqlClient.SqlMethods.Like(row.Name, "test") в моем запросе.

выполняется сравнение без учета регистра.

Я попытался это с помощью лямбда-выражения, и это сработало.

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

Если вы передадите строку без учета регистра в LINQ-to-SQL, она будет передана в SQL без изменений, и сравнение произойдет в базе данных. Если вы хотите сделать сравнение строк без учета регистра в базе данных, все, что вам нужно сделать, это создать лямбда-выражение, которое выполняет сравнение, и поставщик LINQ-to-SQL переведет это выражение в SQL-запрос с неповрежденной строкой.

например этот запрос LINQ:

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

получает переведено на следующий SQL поставщиком LINQ-to-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, что означает, что все должно работать именно так, как вы ожидаете.

для выполнения чувствительных к регистру запросов Linq to Sql объявите поля "string" чувствительными к регистру, указав тип данных сервера с помощью одного из следующих параметров;

varchar(4000) COLLATE SQL_Latin1_General_CP1_CS_AS 

или

nvarchar(Max) COLLATE SQL_Latin1_General_CP1_CS_AS

Примечание ‘ " CS "в приведенных выше типах сортировки означает "чувствительный к регистру".

Это можно ввести в поле "Тип данных сервера"при просмотре свойства с помощью конструктора Visual Studio DBML.

Подробнее см. http://yourdotnetdesignteam.blogspot.com/2010/06/case-sensitive-linq-to-sql-queries.html

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

следующий 2-этапный подход работает для меня (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);
}

иногда значение, хранящееся в базе данных, может содержать пробелы, поэтому запуск этого может быть fail

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 класс

title столбец базы данных

помните, что есть разница между тем, работает ли запрос и работает ли он эффективно! Оператор LINQ преобразуется в T-SQL, когда целью оператора является SQL Server, поэтому вам нужно подумать о T-SQL, который будет создан.

С Помощью Строки.Equals скорее всего (я предполагаю) вернет все строки из SQL Server, а затем сделает сравнение в .NET, потому что это выражение .NET, которое не может быть переведено в Т-SQL.

другими словами, использование выражения увеличит ваш доступ к данным и лишит вас возможности использовать индексы. Он будет работать на небольших столах, и вы не заметите разницы. На большом столе он мог выступать очень плохо.

Это одна из проблем, которая существует с LINQ; люди больше не думают о том, как заявления, которые они писать будут выполнены.

в этом случае нет способа сделать то, что вы хотите без использования выражения-нет даже в T-SQL. Поэтому вы не сможете сделать это более эффективно. Даже ответ T-SQL, приведенный выше (с использованием переменных с параметрами сортировки), скорее всего, приведет к игнорированию индексов, но если это большая таблица, то стоит запустить оператор и посмотреть на план выполнения, чтобы увидеть, был ли использован индекс.