Это не чувствительное к регистру сравнение в LINQ to Entities:
Thingies.First(t => t.Name == "ThingamaBob");
Как я могу получить чувствительное к регистру сравнение с LINQ to Entities?
Это не чувствительное к регистру сравнение в LINQ to Entities:
Thingies.First(t => t.Name == "ThingamaBob");
Как я могу получить чувствительное к регистру сравнение с LINQ to Entities?
Это потому, что вы используете LINQ To Entities, который в конечном итоге преобразует ваши выражения лямбда в выражения SQL. Это означает, что чувствительность к регистру находится во власти вашего SQL Server, который по умолчанию имеет SQL_Latin1_General_CP1_CI_AS, и это НЕ чувствительно к регистру.
Используя 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 затем передается в Object Services 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. Скомпоновать регистр с SQL-запросом..
Единственное решение, которое вы можете применить на стороне клиента, - это использовать LINQ to Objects для еще одного сравнения, которое кажется не очень элегантным:
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);
}
Тогда do
Add-Migration CaseSensitive
Update-Database
на основе статьи 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;
Мне понравился Morteza ответ, и он обычно предпочитает исправлять на стороне сервера. Для клиентской стороны я обычно использую:
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)