Сравнение строк без учета регистра в LINQ-to-SQL - PullRequest
132 голосов
/ 08 мая 2009

Я читал, что неразумно использовать ToUpper и ToLower для сравнения строк без учета регистра, но я не вижу альтернативы, когда речь идет о LINQ-to-SQL. LINQ-to-SQL игнорирует аргументы ignoreCase и CompareOptions в String.Compare (если вы используете базу данных с учетом регистра, вы получаете сравнение с учетом регистра, даже если вы запрашиваете сравнение без учета регистра). Является ли ToLower или ToUpper лучшим вариантом здесь? Один лучше другого? Я думал, что где-то читал, что 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 ]

109 голосов
/ 08 мая 2009

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

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

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

ПРИМЕЧАНИЕ, ОДНАКО что это работает не работает в этом случае! Поэтому мы застряли с ToUpper или ToLower.

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

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

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

71 голосов
/ 26 июня 2009

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

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

6 голосов
/ 01 ноября 2010

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

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

0 голосов
/ 23 мая 2018

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

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 - столбец базы данных

0 голосов
/ 06 декабря 2013
where row.name.StartsWith(q, true, System.Globalization.CultureInfo.CurrentCulture)
0 голосов
/ 06 июня 2013

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

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

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

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

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

0 голосов
/ 24 июня 2011

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

Чтобы выполнить регистрозависимые запросы Linq to Sql, объявите «строковые» поля с учетом регистра, указав тип данных сервера, используя одно из следующих действий:

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

0 голосов
/ 08 мая 2009

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

Например, этот запрос 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, что означает, что все должно работать так, как вы ожидаете.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...