.NET StringComparer가 SQL의 Latin1_General_CI_AS와 동등한 것
-
28-10-2019 - |
문제
데이터베이스와 C # 코드 사이에 캐싱 레이어를 구현하고 있습니다. 아이디어는 쿼리에 대한 매개 변수를 기반으로 특정 DB 쿼리의 결과를 캐시하는 것입니다. 데이터베이스는 기본 데이터 정렬 (SQL_Latin1_General_CP1_CI_AS
또는 Latin1_General_CI_AS
)을 사용하고 있습니다. 일부 간단한 인터넷 검색을 기반으로하는 것은 동등성에 대해 동일하고 정렬에 대해서는 다릅니다.
데이터베이스의 데이터 정렬이 사용하는 것과 같이 적어도 동등성 테스트 및 해시 코드 생성을 위해 동일한 동작을 제공 할 수있는 .NET StringComparer가 필요합니다. 목표는 C # 코드의 .NET 사전에서 StringComparer를 사용하여 특정 문자열 키가 이미 캐시에 있는지 여부를 확인할 수 있도록하는 것입니다.
정말 단순화 된 예 : 라코 디스
StringComparer가 데이터베이스의 데이터 정렬과 일치하는 것이 중요한 이유는 거짓 양성과 거짓 음성이 모두 코드에 나쁜 영향을 미치기 때문입니다.
StringComparer가 데이터베이스가 구별된다고 생각할 때 두 개의 키 A와 B가 동일하다고 말하면 데이터베이스에 두 개의 키가있는 두 개의 행이있을 수 있지만 요청시 캐시는 두 번째 키가 반환되는 것을 방지합니다. A와 B의 연속-get for B가 캐시를 잘못 적중하고 A에 대해 검색된 객체를 반환하기 때문입니다.
데이터베이스가 A와 B가 동일하다고 생각할 때 StringComparer가 A와 B가 다르다고 말하면 문제는 더 미묘하지만 덜 문제가되지는 않습니다. 두 키에 대한 GetObject 호출은 괜찮을 것이며 동일한 데이터베이스 행에 해당하는 개체를 반환합니다. 그러나 키 A로 SaveObject를 호출하면 캐시가 올바르지 않게됩니다. 이전 데이터가있는 키 B에 대한 캐시 항목이 여전히 있습니다. 후속 GetObject (B)는 오래된 정보를 제공합니다. 따라서 내 코드가 올바르게 작동하려면 동등성 테스트 및 해시 코드 생성을위한 데이터베이스 동작과 일치하는 StringComparer가 필요합니다. 지금까지 인터넷 검색을 통해 SQL 데이터 정렬과 .NET 비교가 정확히 동일하지 않다는 사실에 대한 많은 정보를 얻었지만 차이점이 무엇인지, 정렬의 차이로만 제한되는지 또는 찾을 수 있는지 여부에 대한 세부 정보는 없습니다. 범용 솔루션이 필요하지 않은 경우 특정 SQL 데이터 정렬에 해당하는 StringComparer
(참고-캐싱 레이어는 범용이므로 키의 특성과 적절한 데이터 정렬에 대해 특별한 가정을 할 수 없습니다. 데이터베이스의 모든 테이블은 동일한 기본 서버 데이터 정렬을 공유합니다. 존재하는 데이터 정렬과 일치해야 함)
해결책
CollationInfo
를 살펴보십시오. 클래스. 어디서 얻을 수 있는지는 확실하지 않지만 Microsoft.SqlServer.Management.SqlParser.dll
라는 어셈블리에 있습니다. Collations
의 정적 목록이 있습니다. (이름) 및 정적 메서드 GetCollationInfo
(이름 별 ).
각 CollationInfo
에는 가 있습니다. Comparer
. StringComparer
와 정확히 동일하지는 않지만 유사한 기능을 가지고 있습니다.
편집 : Microsoft.SqlServer.Management.SqlParser.dll은 SMO (공유 관리 개체) 패키지의 일부입니다. 이 기능은 여기에서 SQL Server 2008 R2 용으로 다운로드 할 수 있습니다.
http://www.microsoft.com/download/ en / details.aspx? id= 16978 # SMO
편집 : CollationInfo
에는 EqualityComparer
는 IEqualityComparer<string>
입니다.
다른 팁
최근 같은 문제에 직면했습니다. SQL과 유사한 스타일로 작동하는 유전자 태그 코드가 필요합니다. 나는 IEqualityComparer<string>
와 그 CollationInfo
를 시도했습니다. DB가 항상 _AS (악센트 구분)이면 솔루션이 작동하지만 AI 또는 WI 인 데이터 정렬을 변경하는 경우 솔루션이 작동합니다. 또는 "무감각"한 경우 해싱이 중단됩니다.
왜? Microsoft.SqlServer.Management.SqlParser.dll 을 디 컴파일하고 내부를 살펴보면 EqualityComparer
가 내부적으로 CollationInfo
(mscorlib.dll의 내부 클래스)를 사용하고 마지막으로 다음을 수행한다는 것을 알 수 있습니다.
라코 디스
보시다시피 "aa"및 "AA"에 대해 동일한 해시 코드를 생성 할 수 있지만 "äå"및 "aa"에 대해서는 동일하지 않습니다 (대부분의 문화권에서 분음 부호 (AI)를 무시하면 동일합니다. 따라서 동일한 해시 코드를 가져야합니다). .NET API가 이것에 의해 제한되는 이유를 모르겠지만 문제가 어디에서 발생할 수 있는지 이해해야합니다.
분음 부호가있는 문자열에 대해 동일한 해시 코드를 얻으려면 다음을 수행하십시오. 구현 생성 이 메서드는 내부적이며 직접 사용할 수 없기 때문에 적절한 CultureAwareComparer.GetHashCode
의 객체의 IEqualityComparer<T>
를 리플렉션을 통해 호출하는 GetHashCode
를 구현하는 CompareInfo
의. 그러나 올바른 GetHashCodeOfString
로 직접 호출하면 원하는 결과가 생성됩니다.
다음 예를 참조하세요.
라코 디스
출력은 다음과 같습니다. 라코 디스
나는 그것이 해킹처럼 보이는 것을 알고 있지만, 디 컴파일 된 .NET 코드를 조사한 후에 일반 기능이 필요한 경우에 다른 옵션이 있는지 확실하지 않습니다.
따라서 완전히 정확하지 않은 API를 사용하여 함정에 빠지지 않도록하십시오.
업데이트 :
또한 "SQL과 유사한 비교 자"의 잠재적 구현에 대한 요점을 만들었습니다. CompareOptions
사용.
또한 충분한주의를 기울여야합니다. "string pitfalls"를 검색 할 수있는 위치 코드 기반에서 문자열 비교, 해시 코드, 동등성을 "SQL 데이터 정렬과 유사"로 변경해야하는 경우 해당 위치가 100 % 손상되므로 가능한 모든 위치를 찾아서 검사해야합니다. 부서진다.
업데이트 # 2 :
GetHashCode ()가 CompareOptions를 처리하도록하는 더 좋고 깨끗한 방법이 있습니다. 클래스 SortKey 는 CompareOptions와 올바르게 작동하며 를 사용하여 검색 할 수 있습니다.
<인용구>
CompareInfo.GetSortKey (yourString, yourCompareOptions) .GetHashCode ()
다음은 .NET 소스 코드에 대한 링크 입니다. 및 구현.
SQL Server의 Server.GetStringComparer 가 유용 할 수 있습니다.
다음은 훨씬 간단합니다. 라코 디스
주어진 옵션이 주어지면 해시 코드를 올바르게 계산합니다. 후행 공백은 ANSI SQL에서 삭제되지만 .net에서는 삭제되지 않으므로 수동으로 정리해야합니다.
다음은 공백을 정리하는 래퍼입니다. 라코 디스