LINQ to Entities에서는 대 / 소문자를 구분하지 않습니다.
Thingies.First(t => t.Name == "ThingamaBob");
LINQ to Entities와 대 / 소문자 구분 비교를 수행하려면 어떻게해야합니까?
답변
궁극적으로 Lambda 식을 SQL 문으로 변환하는 LINQ To Entities 를 사용하고 있기 때문 입니다. 즉, 대소 문자 구분은 기본적으로 SQL_Latin1_General_CP1_CI_AS 데이터 정렬이 있고 대소 문자를 구분하지 않는 SQL Server의 자비에 있습니다 .
ObjectQuery.ToTraceString 을 사용하여 실제로 SQL Server에 제출 된 생성 된 SQL 쿼리를 확인하면 수수께끼가 드러납니다.
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는 항상 동일하게 처리합니다.
서버 측 솔루션 :
따라서 가장 좋은 해결책은 Thingies 테이블 의 Name 열 데이터 정렬을 SQL Server에서 실행하여 대소 문자를 구분하는 COLLATE Latin1_General_CS_AS로 변경 하는 것입니다.
ALTER TABLE Thingies
ALTER COLUMN Name VARCHAR(25)
COLLATE Latin1_General_CS_AS
SQL Server Collate 에 대한 자세한 내용 은 SQL SERVER Collate 대소 문자 구분 SQL 쿼리 검색을 참조하십시오.
클라이언트 측 솔루션 :
클라이언트 측에 적용 할 수있는 유일한 솔루션은 LINQ to Objects 를 사용 하여 그다지 우아하지 않은 또 다른 비교를 수행하는 것입니다.
Thingies.Where(t => t.Name == "ThingamaBob")
.AsEnumerable()
.First(t => t.Name == "ThingamaBob");
답변
EF6 + 코드 우선에 대한 [CaseSensitive] 주석을 추가 할 수 있습니다.
이 수업 추가
[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);
}
그런 다음
추가 마이그레이션 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");
}
그러나
새로운 EF6 기능을 사용하여 “CaseSensitive”라는 사용자 지정 주석을 만들 수 있으며 다음과 같이 속성을 장식 할 수 있습니다.
[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);