Сравнение строк в LINQ-to-SQL

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

Ответ 1

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

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

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

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

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

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

Ответ 2

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

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

Ответ 3

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

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

Ответ 4

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

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

from user in Users
where user.Email == "[email protected]"
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 "[email protected]"

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

Ответ 5

Для выполнения чувствительных к регистру запросов 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

Ответ 6

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

Ответ 7

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

Ответ 8

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

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

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

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

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