Це не порівнянне з великим регістром порівняння LINQ до об'єктів:
Thingies.First(t => t.Name == "ThingamaBob");
Як я можу домогтися порівняння з великим регістром порівняння з LINQ до організацій?
Це не порівнянне з великим регістром порівняння LINQ до об'єктів:
Thingies.First(t => t.Name == "ThingamaBob");
Як я можу домогтися порівняння з великим регістром порівняння з LINQ до організацій?
Відповіді:
Це тому, що ви використовуєте LINQ To Entities, що в кінцевому підсумку перетворює ваші лямбда-вирази в оператори SQL. Це означає, що чутливість регістру належить на розсуд вашого сервера SQL, який за замовчуванням має SQL_Latin1_General_CP1_CI_AS Collation, і він НЕ враховує регістри .
Використовуючи ObjectQuery.ToTraceString, щоб побачити згенерований SQL-запит, який був фактично поданий на SQL Server, розкриває таємницю:
string sqlQuery = ((ObjectQuery)context.Thingies
.Where(t => t.Name == "ThingamaBob")).ToTraceString();
Коли ви створюєте запит LINQ до Entities , LINQ to Entities використовує парсер LINQ для початку обробки запиту і перетворює його в дерево вираження LINQ. Потім дерево виразів LINQ передається в API об’єктних служб , який перетворює дерево виразів у дерево команд. Потім він надсилається постачальнику магазину (наприклад, SqlClient), який перетворює дерево команд у рідний текст команди бази даних. Query отримати виконується в сховище даних , і результати Матеріалізовані в Entity об'єктів по обслуговуванню об'єктів. Жодна логіка між ними не враховувала чутливість до справ. Таким чином, незалежно від того, у якому випадку ви ставите свій предикат, він завжди вважатиметься вашим SQL сервером таким самим, якщо ви не зміните SQL Server Collati для цього стовпця.
Тому найкращим рішенням було б змінити зіставлення стовпця " Ім'я " в таблиці Thingies на COLLATE Latin1_General_CS_AS, який залежно від регістру, запустивши це на вашому SQL Server:
ALTER TABLE Thingies
ALTER COLUMN Name VARCHAR(25)
COLLATE Latin1_General_CS_AS
Щоб отримати додаткові відомості про SQL Server Collati , подивіться на пошук SQL SERVER Collate Sensitive SQL Query Search
Єдине рішення, яке можна застосувати на стороні клієнта, - це використовувати LINQ для об’єктів, щоб зробити ще одне порівняння, яке не дуже елегантно:
Thingies.Where(t => t.Name == "ThingamaBob")
.AsEnumerable()
.First(t => t.Name == "ThingamaBob");
Ви можете додати анотацію [CaseSensitive] для EF6 + Code-first
Додайте ці класи
[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<CaseSensitiveAttribute, bool>(
"CaseSensitive",
(property, attributes) => attributes.Single().IsEnabled));
base.OnModelCreating(modelBuilder);
}
Тоді робіть
Справа щодо міграції, сприйнятлива
Оновлення-база даних
на основі статті 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()));
How can I achieve case sensitive comparison
Використовуйте 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)
StringComparison
перелік, щоб змінити ситуацію. Я бачив досить багато людей , які передбачають такого роду речі повинні працювати , щоб думати , що проблема де - то в файлі EDMX (DB-перше), хоча stackoverflow.com/questions/841226 / ...