LINQ-to-SQL에서 대소 문자를 구분하지 않는 문자열 비교


137

ToUpper와 ToLower를 사용하여 대소 문자를 구분하지 않는 문자열 비교를 수행하는 것이 현명하지 않다는 것을 읽었지만 LINQ-to-SQL과 관련하여 대안이 없습니다. String.Compare의 ignoreCase 및 CompareOptions 인수는 LINQ-to-SQL에서 무시됩니다 (대소 문자를 구분하는 데이터베이스를 사용하는 경우 대소 문자를 구분하지 않는 비교를 요청하더라도 대소 문자를 구분합니다). ToLower 또는 ToUpper가 가장 적합한 옵션입니까? 하나는 다른 것보다 낫습니까? 어딘가 ToUpper가 더 낫다는 것을 읽었지만 여기에 적용되는지 모르겠습니다. (나는 많은 코드 검토를하고 있으며 모두가 ToLower를 사용하고 있습니다.)

Dim s = From row In context.Table Where String.Compare(row.Name, "test", StringComparison.InvariantCultureIgnoreCase) = 0

이것은 단순히 row.Name을 "test"와 비교하는 SQL 쿼리로 변환되며 대소 ​​문자를 구분하는 데이터베이스에서 "Test"및 "TEST"를 반환하지 않습니다.


1
감사! 오늘 정말 내 엉덩이를 구했습니다. 참고 : LINQQuery.Contains("VaLuE", StringComparer.CurrentCultureIgnoreCase)및 다른 LINQ 확장과도 작동합니다 LINQQuery.Except(new string[]{"A VaLUE","AnOTher VaLUE"}, StringComparer.CurrentCultureIgnoreCase). 와후!
Greg Bray

재미 있지만, 나는 ToUpper가이 소스와 비교했을 때 더 낫다는 것을 읽었습니다. msdn.microsoft.com/en-us/library/dd465121
malckier

답변:


110

당신이 말했듯이, ToUpper와 ToLower 사이에는 중요한 차이점이 있으며 대소 문자를 구분하지 않는 동등성 검사를 수행하려고 할 때 단 하나만 정확합니다.

대소 문자를 구분하지 않는 동등성 검사를 수행하는 가장 좋은 방법 은 다음과 같습니다.

String.Equals(row.Name, "test", StringComparison.OrdinalIgnoreCase)

그러나이 경우에는 작동 하지 않습니다 ! 따라서 우리는 ToUpper또는 로 붙어 있습니다 ToLower.

보안 안전을 위해 서수 IgnoreCase를 참고하십시오 . 그러나 사용하는 대소 문자를 구분하여 정확히 검사하는 목적은 용도에 따라 다릅니다. 그러나 일반적으로 등식 검사에 대해 동일을 사용하고 정렬 할 때 비교를 사용한 다음 작업에 적합한 StringComparison을 선택하십시오.

마이클 카플란 (Michael Kaplan) (이와 같은 문화 및 캐릭터 취급에 대한 인정 된 당국)은 ToUpper와 ToLower에 대한 관련 게시물을 보유하고 있습니다.

"- String.ToUpper 그는 말한다 사용의 ToUpper보다는 ToLower는, 그리고 OS 케이스 규칙을 선택하기 위해 InvariantCulture를 지정 "


1
그것은이 SQL Server에 적용되지 않는 것 같다 인쇄를 위 ( '그로 스트 라스')는 그로 트 반환
BlueMonkMN

1
또한 제공 한 샘플 코드는 MS SQL 2005 데이터베이스에서 LINQ-to-SQL을 통해 실행할 때 대 / 소문자를 구분하는 한 제공 한 코드와 동일한 문제가 있습니다.
BlueMonkMN

2
나는 동의한다. 불분명해서 죄송합니다. 원래 질문에서 지적했듯이 내가 제공 한 샘플 코드는 Linq2Sql에서 작동하지 않습니다. 나는 단지 당신이 시작한 방식이이 시나리오에서만 효과가 있었다면 갈 수있는 좋은 방법이라는 것을 다시 한 번 쉬고있었습니다. 그리고 또 다른 Mike Kaplan soapbox는 SQL Server의 문자 처리가 어디에나 있다는 것입니다. 대소 문자를 구분하지 않고 다른 방법으로 얻을 수없는 경우 데이터를 대문자로 저장 한 다음 대문자로 쿼리하는 것이 좋습니다.
Andrew Arnott

3
대소 문자를 구분하는 데이터베이스가 있고 대소 문자를 혼합하여 저장하고 대문자로 검색하면 일치하는 항목이 없습니다. 검색에서 데이터와 쿼리를 모두 대문자로 만들면 검색하지 않는 모든 텍스트를 모든 쿼리에 대해 변환합니다 (성능이 아님).
Andrew Arnott

1
@BlueMonkMN, 올바른 스 니펫을 붙여 넣었습니까? MSSQL 서버가 검정보다 빨강을 선호한다고 믿기가 어렵습니다.
greenoldman

75

System.Data.Linq.SqlClient.SqlMethods.Like(row.Name, "test") 내 쿼리에 사용 했습니다.

대소 문자를 구분하지 않는 비교를 수행합니다.


3
하아! linq 2 sql을 몇 년 동안 사용했지만 지금까지 SqlMethods를 보지 못했습니다. 감사합니다!
Carl Hörberg

3
훌륭한! 그러나 더 자세한 내용을 사용할 수 있습니다. 이것은 Like의 예상되는 용도 중 하나입니까? 오탐 (false positive) 결과를 초래할 수있는 입력이 있습니까? 아니면 잘못된 부정적인 결과? 이 방법에 대한 설명서는 어디 문서의, 부족 합니다 좋아요 방법의 동작을 설명하는가?
작업

2
SQL Server가 문자열을 어떻게 비교하는지에 달려 있다고 생각합니다. 어딘가에서 구성 할 수 있습니다.
Andrew Davey

11
System.Data.Linq.SqlClient.SqlMethods.Like (row.Name, "test")는 row.Name.Contains ( "test")와 같습니다. Andrew가 말했듯이 이것은 SQL Server의 데이터 정렬에 따라 다릅니다. 따라서 Like (또는 포함)가 대소 문자를 구분하지 않는 비교를 항상 수행하지는 않습니다.
doekman 2016 년

3
이로 인해 코드가 너무 결합됩니다 SqlClient.
Jaider

5

나는 Lambda 식을 사용하여 이것을 시도했지만 효과가있었습니다.

List<MyList>.Any (x => (String.Equals(x.Name, name, StringComparison.OrdinalIgnoreCase)) && (x.Type == qbType) );


18
이는을 사용하기 때문 입니다. 이는 데이터베이스 에서 비교 수행 List<>하는 IQueryable(또는 ObjectQuery) 대신 메모리 내 (C # 코드) 비교가 수행됨을 의미 합니다 .
drzaus

1
@drzaus가 말한 것. 이 답변은 컨텍스트가 일반 linq가 아니라 linq2sql이라는 점을 고려하면 간단하지 않습니다.
rsenna 2016 년

0

LINQ-to-SQL에 대소 문자를 구분하지 않는 문자열을 전달하면 변경되지 않은 SQL로 전달되고 비교는 데이터베이스에서 수행됩니다. 데이터베이스에서 대소 문자를 구분하지 않는 문자열 비교를 수행하려면 비교를 수행하는 람다 식을 만들고 LINQ-to-SQL 공급자는 해당 식을 문자열이 그대로있는 SQL 쿼리로 변환합니다.

예를 들어이 LINQ 쿼리는 다음과 같습니다.

from user in Users
where user.Email == "foo@bar.com"
select user

LINQ-to-SQL 공급자가 다음 SQL로 변환합니다.

SELECT [t0].[Email]
FROM [User] AS [t0]
WHERE [t0].[Email] = @p0
-- note that "@p0" is defined as nvarchar(11)
-- and is passed my value of "foo@bar.com"

보시다시피, 문자열 매개 변수는 SQL에서 비교됩니다. 즉, 예상 한대로 작동해야합니다.


나는 당신이 무슨 말을하는지 이해하지 못합니다. 1) 문자열 자체는 .NET에서 대소 문자를 구분하지 않거나 대소 문자를 구분할 수 없으므로 "대소 문자를 구분하지 않는 문자열"을 전달할 수 없습니다. 2) LINQ 쿼리는 기본적으로 람다 식이므로 두 문자열을 전달하는 방식이므로 나에게 의미가 없습니다.
BlueMonkMN

3
CASE-SENSITIVE 데이터베이스에서 CASE-INSENSITIVE 비교를 수행하고 싶습니다.
BlueMonkMN

어떤 CASE-SENSITIVE 데이터베이스를 사용하고 있습니까?
앤드류 헤어

또한 LINQ 쿼리는 람다식이 아닙니다. LINQ 쿼리는 여러 부분 (주로 쿼리 연산자 및 람다 식)으로 구성됩니다.
앤드류 헤어

이 답변은 BlueMonkMN 의견으로는 의미가 없습니다.
Alf

0

대 / 소문자를 구분하는 Linq-Sql 쿼리를 수행하려면 다음 중 하나를 사용하여 서버 데이터 형식을 지정하여 'string'필드를 대 / 소문자를 구분합니다.

varchar(4000) COLLATE SQL_Latin1_General_CP1_CS_AS 

또는

nvarchar(Max) COLLATE SQL_Latin1_General_CP1_CS_AS

참고 : 위 데이터 정렬 유형에서 'CS'는 '대소 문자 구분'을 의미합니다.

Visual Studio DBML Designer를 사용하여 속성을 볼 때“서버 데이터 형식”필드에 입력 할 수 있습니다.

자세한 내용은 http://yourdotnetdesignteam.blogspot.com/2010/06/case-sensitive-linq-to-sql-queries.html을


그게 문제입니다. 일반적으로 사용하는 필드는 대소 문자를 구분합니다 (화학식 CO [일산화탄소]는 Co [코발트]와 다릅니다). 그러나 특정 상황 (검색)에서 co와 CO를 모두 일치시키기를 원합니다. 다른 "server data type"으로 추가 속성을 정의하는 것은 합법적이지 않습니다 (linq to sql은 sql 열당 하나의 속성 만 허용합니다). 아직 갈 수 없습니다.
doekman 2016 년

또한 단위 테스트를 수행하는 경우이 방법은 데이터 모의와 호환되지 않을 것입니다. 허용 된 답변에서 linq / lambda 접근 방식을 사용하는 것이 가장 좋습니다.
Derrick

0
where row.name.StartsWith(q, true, System.Globalization.CultureInfo.CurrentCulture)

1
이것이 번역되는 SQL 텍스트는 무엇이며, SQL 환경에서 대소 문자를 구분하지 않는 대소 문자를 구분할 수있는 것은 무엇입니까?
BlueMonkMN

0

다음 2 단계 접근 방식이 저에게 효과적입니다 (VS2010, ASP.NET MVC3, SQL Server 2008, Linq to SQL).

result = entRepos.FindAllEntities()
    .Where(e => e.EntitySearchText.Contains(item));

if (caseSensitive)
{
    result = result
        .Where(e => e.EntitySearchText.IndexOf(item, System.StringComparison.CurrentCulture) >= 0);
}

1
텍스트가 검색 텍스트 (> = 0이어야 함)로 시작하면이 코드에 버그가 있습니다.
Flatliner DOA

@FlatlinerDOA 실제로해야 != -1하기 때문에 IndexOf "-1을 반환 문자 또는 문자열이 발견되지 않는 경우"
drzaus

0

때로는 데이터베이스에 저장된 값에 공백이 포함될 수 있으므로 실행이 실패 할 수 있습니다.

String.Equals(row.Name, "test", StringComparison.OrdinalIgnoreCase)

이 문제에 대한 해결책은 공간을 제거한 다음 케이스를 변환하고 다음과 같이 선택하는 것입니다.

 return db.UsersTBs.Where(x => x.title.ToString().ToLower().Replace(" ",string.Empty).Equals(customname.ToLower())).FirstOrDefault();

이 경우 참고

customname 은 데이터베이스 값과 일치하는 값입니다.

사용자 TB 는 클래스입니다

제목 은 데이터베이스 열입니다


-1

쿼리가 작동하는지와 효율적으로 작동하는지에 차이가 있음을 기억하십시오 ! 문의 대상이 SQL Server 인 경우 LINQ 문은 T-SQL로 변환되므로 생성 될 T-SQL에 대해 고려해야합니다.

String.Equals를 사용하면 SQL Server에서 모든 행을 다시 가져온 다음 .NET에서 비교를 수행합니다 .T-SQL로 변환 할 수없는 .NET 표현식이기 때문입니다.

즉, 식을 사용하면 데이터 액세스가 증가하고 인덱스를 사용하는 기능이 제거됩니다. 작은 테이블에서 작동하며 차이점을 알 수 없습니다. 큰 테이블에서는 성능이 매우 떨어질 수 있습니다.

이것이 LINQ에 존재하는 문제 중 하나입니다. 사람들은 더 이상 자신이 작성한 진술이 어떻게 이행 될지에 대해 생각하지 않습니다.

이 경우 식을 사용하지 않고 원하는 작업을 수행 할 수있는 방법이 없습니다. 심지어 T-SQL에서도 마찬가지입니다. 따라서이 작업을 더 효율적으로 수행하지 못할 수 있습니다. 위에서 주어진 T-SQL 응답 (배열과 함께 변수 사용)조차도 인덱스가 무시 될 가능성이 높지만 큰 테이블 인 경우 명령문을 실행하고 인덱스가 사용되었는지 확인하기 위해 실행 계획을 살펴볼 가치가 있습니다. .


2
사실이 아닙니다 (행이 클라이언트에 반환되지는 않습니다). String.Equals를 사용했는데 작동하지 않는 이유는 데이터베이스 또는 서버의 데이터 정렬에 따라 동작이 TSQL 문자열 비교로 변환되기 때문입니다. 필자가 작성한 모든 LINQ to SQL 표현식이 TSQL로 변환되는 방식을 고려합니다. 내가 원하는 것을하는 방법은 ToUpper를 사용하여 생성 된 TSQL이 UPPER을 사용하도록하는 것입니다. 그런 다음 모든 변환 및 비교 논리가 여전히 TSQL에서 수행되므로 성능이 크게 저하되지 않습니다.
BlueMonkMN 2016 년
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.