Сравнение строк без учета регистра в 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 ответов:
Как вы говорите, есть некоторые важные различия между 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
следующий 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, приведенный выше (с использованием переменных с параметрами сортировки), скорее всего, приведет к игнорированию индексов, но если это большая таблица, то стоит запустить оператор и посмотреть на план выполнения, чтобы увидеть, был ли использован индекс.