Сравнение с регистром LINQ to Entities

Это не чувствительное к регистру сравнение в LINQ с объектами:

Thingies.First(t => t.Name == "ThingamaBob"); 

Как я могу получить сравнение чувствительности к регистру с LINQ к объектам?

Это потому, что вы используете LINQ To Entities, который в конечном итоге преобразует ваши выражения Lambda в SQL-выражения. Это означает, что чувствительность к регистру находится во власти вашего SQL Server, который по умолчанию имеет SQL_Latin1_General_CP1_CI_AS Collation и не чувствителен к регистру.

Использование ObjectQuery.ToTraceString для просмотра сгенерированного SQL-запроса, который был фактически отправлен на SQL Server, раскрывает тайну:

 string sqlQuery = ((ObjectQuery)context.Thingies .Where(t => t.Name == "ThingamaBob")).ToTraceString(); 

Когда вы создаете запрос LINQ to Entities , LINQ to Entities использует анализатор LINQ для начала обработки запроса и преобразования его в дерево выражений LINQ. Дерево выражений LINQ затем передается API-интерфейсу объектов , который преобразует дерево выражений в дерево команд. Затем он отправляется поставщику магазина (например, SqlClient), который преобразует дерево команд в текст команды основной базы данных. Запрос выполняется в хранилище данных, и результаты материализуются в объекты объектов через службы объектов . Никакая логика не была вставлена ​​между ними, чтобы учитывать чувствительность к регистру. Поэтому независимо от того, в каком случае вы помещаете в свой предикат, он всегда будет рассматривать одно и то же на вашем SQL Server, если вы не измените ваши SQL Server Collates для этого столбца.

Решение на стороне сервера:

Поэтому лучшим решением было бы изменить сортировку столбца Name в таблице Thingies в COLLATE Latin1_General_CS_AS, которая чувствительна к регистру, выполнив это на вашем SQL Server:

 ALTER TABLE Thingies ALTER COLUMN Name VARCHAR(25) COLLATE Latin1_General_CS_AS 

Для получения дополнительной информации о SQL Server Collates рассмотрите SQL SERVER.

Клиентское решение:

Единственным решением, которое вы можете применить на стороне клиента, является использование LINQ to Objects для проведения еще одного сравнения, которое не кажется очень элегантным:

 Thingies.Where(t => t.Name == "ThingamaBob") .AsEnumerable() .First(t => t.Name == "ThingamaBob"); 

Вы можете добавить аннотацию [CaseSensitive] для EF6 + Code-first

Добавить эти classы

 [AttributeUsage(AttributeTargets.Property, AllowMultiple = true)] public class CaseSensitiveAttribute : Attribute { public CaseSensitiveAttribute() { IsEnabled = true; } public bool IsEnabled { get; set; } } public class CustomSqlServerMigrationSqlGenerator : SqlServerMigrationSqlGenerator { protected override void Generate(AlterColumnOperation alterColumnOperation) { base.Generate(alterColumnOperation); AnnotationValues values; if (alterColumnOperation.Column.Annotations.TryGetValue("CaseSensitive", out values)) { if (values.NewValue != null && values.NewValue.ToString() == "True") { using (var writer = Writer()) { //if (System.Diagnostics.Debugger.IsAttached == false) System.Diagnostics.Debugger.Launch(); // https://github.com/mono/entityframework/blob/master/src/EntityFramework.SqlServer/SqlServerMigrationSqlGenerator.cs var columnSQL = BuildColumnType(alterColumnOperation.Column); //[nvarchar](100) writer.WriteLine( "ALTER TABLE {0} ALTER COLUMN {1} {2} COLLATE SQL_Latin1_General_CP1_CS_AS {3}", alterColumnOperation.Table, alterColumnOperation.Column.Name, columnSQL, alterColumnOperation.Column.IsNullable.HasValue == false || alterColumnOperation.Column.IsNullable.Value == true ? " NULL" : "NOT NULL" //todo not tested for DefaultValue ); Statement(writer); } } } } } public class CustomApplicationDbConfiguration : DbConfiguration { public CustomApplicationDbConfiguration() { SetMigrationSqlGenerator( SqlProviderServices.ProviderInvariantName, () => new CustomSqlServerMigrationSqlGenerator()); } } 

Измените свой DbContext, добавьте

 protected override void OnModelCreating(DbModelBuilder modelBuilder) { modelBuilder.Conventions.Add(new AttributeToColumnAnnotationConvention( "CaseSensitive", (property, attributes) => attributes.Single().IsEnabled)); base.OnModelCreating(modelBuilder); } 

Тогда сделайте

Add-Migration CaseSensitive

Обновление базы данных

на основе статьи https://milinaudara.wordpress.com/2015/02/04/case-sensitive-search-using-entity-framework-with-custom-annotation/ с исправлением ошибок

Условия WHERE в SQL Server по умолчанию нечувствительны к регистру. Сделайте регистр чувствительным к регистру, изменив сопоставления по умолчанию столбца ( SQL_Latin1_General_CP1_CI_AS ) на SQL_Latin1_General_CP1_CS_AS .

Хрупкий способ сделать это – с кодом. Добавьте новый файл миграции, а затем добавьте его внутри метода Up :

 public override void Up() { Sql("ALTER TABLE Thingies ALTER COLUMN Name VARCHAR(MAX) COLLATE SQL_Latin1_General_CP1_CS_AS NOT NULL"); } 

Но

Вы можете создать пользовательскую аннотацию под названием «CaseSensitive», используя новые функции EF6, и вы можете украсить свои свойства следующим образом:

 [CaseSensitive] public string Name { get; set; } 

В этом блоге объясняется, как это сделать.

Ответ, данный @Morteza Manavi, решает проблему. Тем не менее, для клиентского решения элегантный способ был бы следующим (добавив двойную проверку).

 var firstCheck = Thingies.Where(t => t.Name == "ThingamaBob") .FirstOrDefault(); var doubleCheck = (firstCheck.Name == model.Name) ? Thingies : null; 

Мне понравился ответ Мортезы, и он обычно предпочитает исправлять на стороне сервера. Для клиентской стороны я обычно использую:

 Dim bLogin As Boolean = False Dim oUser As User = (From c In db.Users Where c.Username = UserName AndAlso c.Password = Password Select c).SingleOrDefault() If oUser IsNot Nothing Then If oUser.Password = Password Then bLogin = True End If End If 

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

Ни один из StringComparison.IgnoreCase работал для меня. Но это произошло:

 context.MyEntities.Where(p => p.Email.ToUpper().Equals(muser.Email.ToUpper())); 

Использовать string.Equals

 Thingies.First(t => string.Equals(t.Name, "ThingamaBob", StringComparison.CurrentCulture); 

Кроме того, вам не нужно беспокоиться о null и возвращать только нужную вам информацию.

Используйте StringComparision.CurrentCultureIgnoreCase для нечувствительности к регистру.

 Thingies.First(t => string.Equals(t.Name, "ThingamaBob", StringComparison.CurrentCultureIgnoreCase); 

Не уверен в EF4, но EF5 поддерживает это:

 Thingies .First(t => t.Name.Equals( "ThingamaBob", System.StringComparison.InvariantCultureIgnoreCase) 
  • Указанный член типа не поддерживается в LINQ to Entities. Поддерживаются только инициализаторы, сущности и свойства навигации сущности
  • Лучший способ проверить, существует ли объект в Entity Framework?
  • ASP.NET MVC 2.0 Реализация поиска в jqgrid
  • Возможна ли инъекция через динамический LINQ?
  • Как сделать массовую вставку - Linq для объектов
  • 'Содержит ()' обходной путь с использованием Linq для Entities?
  • Получить функцию результата в LINQ без перевода для сохранения выражения
  • Предложение "NOT IN" в LINQ to Entities
  • Как выполнить сравнение даты в запросе EF?
  • Linq to Entities, случайный порядок
  • Включить внуков в EF Query
  • Давайте будем гением компьютера.