[c#] LINQ to Entities 대소 문자 구분 비교

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/ 기사를 기반으로 일부 버그 수정


답변

WHERESQL 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);