LINQ-to-SQL'de büyük / küçük harf duyarsız dize karşılaştırması


137

Küçük harf duyarsız dize karşılaştırmaları gerçekleştirmek için ToUpper ve ToLower kullanmanın akıllıca olmadığını okudum, ancak LINQ-SQL söz konusu olduğunda alternatif görmüyorum. String.Compare öğesinin ignoreCase ve CompareOptions bağımsız değişkenleri LINQ-to-SQL tarafından yoksayılır (büyük / küçük harfe duyarlı bir veritabanı kullanıyorsanız, büyük / küçük harfe duyarlı olmayan bir karşılaştırma isteseniz bile büyük / küçük harfe duyarlı bir karşılaştırma elde edersiniz). ToLower veya ToUpper burada en iyi seçenek mi? Biri diğerinden daha iyi mi? Bir yerde ToUpper'ın daha iyi olduğunu okuduğumu sanıyordum, ama burada geçerli olup olmadığını bilmiyorum. (Kod incelemeleri çok yapıyorum ve herkes ToLower kullanıyor.)

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

Bu, row.Name öğesini "test" ile karşılaştıran ve büyük / küçük harf duyarlı bir veritabanında "Test" ve "TEST" döndürmeyecek bir SQL sorgusuna dönüşür.


1
Teşekkürler! Bu gerçekten kıçımı bugün kurtardı. Not: LINQQuery.Contains("VaLuE", StringComparer.CurrentCultureIgnoreCase)ve gibi diğer LINQ uzantılarıyla da çalışır LINQQuery.Except(new string[]{"A VaLUE","AnOTher VaLUE"}, StringComparer.CurrentCultureIgnoreCase). Wahoo!
Greg Bray

Komik, sadece
ToUpper'ın

Yanıtlar:


110

Söylediğiniz gibi, ToUpper ve ToLower arasında bazı önemli farklılıklar vardır ve büyük / küçük harfe duyarlı olmayan eşitlik kontrolleri yapmaya çalıştığınızda yalnızca biri güvenilirdir.

İdeal olarak, bir küçük harf duyarsız eşitliği denetimini yapmanın en iyi yolu olacağını :

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

NOT ANCAK bu olmadığını çalışmıyor bu durumda! Bu nedenle ToUpperveya ile sıkışıp kaldık ToLower.

Güvenliği güvenli hale getirmek için Ordinal IgnoreCase öğesini not edin . Ancak tam olarak kullandığınız büyük / küçük harf duyarlı kontrol türü, amaçlarınızın ne olduğuna bağlıdır. Ancak genel olarak eşitlik denetimleri için Eşittir seçeneğini kullanın ve sıralarken karşılaştırın ve iş için doğru StringComparison öğesini seçin.

Michael Kaplan (kültür ve karakter kullanımı konusunda tanınmış bir otorite), ToUpper ve ToLower hakkında ilgili yayınlara sahiptir:

"String.ToUpper - ToLower yerine ToUpper kullanın ve işletim sistemi kasa kurallarını almak için InvariantCulture'u belirtin " diyor.


1
Bu SQL Server için geçerli değil gibi görünüyor: print upper ('Große Straße'), GROßE STRAßE
BlueMonkMN

1
Ayrıca, sağladığınız örnek kod, MS SQL 2005 veritabanında LINQ-to-SQL aracılığıyla çalıştırıldığında büyük / küçük harfe duyarlı olarak sağladığım kodla aynı soruna sahiptir.
BlueMonkMN

2
Katılıyorum. Üzgünüm belirsizdim. Sağladığım örnek kod, orijinal sorunuzda belirttiğiniz gibi Linq2Sql ile çalışmaz. Sadece bu senaryoda işe yaradıysa, başlangıç ​​şeklinizin gitmek için harika bir yol olduğunu yeniden söylüyordum. Ve evet, başka bir Mike Kaplan sabun kutusu, SQL Server'ın karakter işlemesinin her yerde olması. Büyük / küçük harf duyarsız ihtiyacınız varsa ve başka bir şekilde elde edemezseniz, (belirsiz bir şekilde) verileri Büyük harf olarak depolamanızı ve daha sonra büyük harf olarak sormanızı öneriyordum.
Andrew Arnott

3
Büyük / küçük harfe duyarlı bir veritabanınız varsa ve karma büyüklükte saklayıp Büyük harfli arama yaparsanız, eşleşme elde edemezsiniz. Aramanızdaki hem verileri hem de sorguyu öne çıkarırsanız, aradığınız tüm metinleri, performans göstermeyen her sorgu için dönüştürürsünüz.
Andrew Arnott

1
@BlueMonkMN, doğru parçacıkları yapıştırdığınızdan emin misiniz? MSSQL Server'ın Kırmızı'yı Siyahtan daha fazla tercih ettiğine inanmak zor.
greenoldman

75

Sorgumda kullandım System.Data.Linq.SqlClient.SqlMethods.Like(row.Name, "test") .

Bu, büyük / küçük harfe duyarlı olmayan bir karşılaştırma yapar.


3
Ha! birkaç yıldır linq 2 sql kullanıyor ama şimdiye kadar SqlMethods görmemişti, teşekkürler!
Carl Hörberg

3
Parlak! Yine de daha fazla ayrıntı kullanabilirsiniz. Bu Like'ın beklenen kullanımlarından biri mi? Yanlış pozitif sonuca neden olabilecek olası girdiler var mı? Ya da yanlış negatif sonuç? Bu yöntem üzerinde dokümantasyon nerede belgeler var, eksik olacak gibi yönteminin işleyişini açıklar?
Görev

2
Ben sadece SQL Server muhtemelen bir yerde yapılandırılabilir dizeleri karşılaştırmak dayanıyor düşünüyorum.
Andrew Davey

11
System.Data.Linq.SqlClient.SqlMethods.Like (row.Name, "test") row.Name.Contains ("test") ile aynıdır. Andrew'un dediği gibi bu, sql sunucusunun harmanlamasına bağlıdır. Yani Like (veya içeren) her zaman büyük / küçük harfe duyarlı olmayan bir karşılaştırma yapmaz.
doekman

3
Unutmayın, bu kod için çok çift olun SqlClient.
Jaider

5

Bunu Lambda ifadesini kullanarak denedim ve işe yaradı.

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


18
Bunun nedeni List<>, a kullanmanızdır ; bu, karşılaştırmanın veritabanında karşılaştırmayı gerçekleştirecek bir IQueryable(veya ObjectQuery) yerine bellek içi (C # kodu) gerçekleştiği anlamına gelir .
drzaus

1
@ Drzaus ne dedi. Bağlamın normal linq değil linq2sql olduğu düşünüldüğünde, bu cevap basitçe yanlıştır.
rsenna

0

LINQ-SQL'e büyük / küçük harfe duyarlı olmayan bir dize iletirseniz, SQL değişmeden geçer ve karşılaştırma veritabanında gerçekleşir. Veritabanında büyük / küçük harfe duyarsız dize karşılaştırmaları yapmak istiyorsanız, yapmanız gereken tek şey karşılaştırmayı yapan bir lambda ifadesi oluşturmaktır ve LINQ-to-SQL sağlayıcısı bu ifadeyi dize bozulmamış bir SQL sorgusuna çevirecektir.

Örneğin, bu LINQ sorgusu:

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

LINQ-to-SQL sağlayıcısı tarafından aşağıdaki SQL'e çevrilir:

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"

Gördüğünüz gibi, string parametresi SQL'de karşılaştırılacaktır, bu da işlerin beklediğiniz gibi çalışması gerektiği anlamına gelir.


Ne dediğini anlamıyorum. 1) Dizelerin kendileri .NET'de büyük / küçük harfe duyarsız veya büyük / küçük harfe duyarlı olamaz, bu nedenle "büyük / küçük harf duyarlı olmayan bir dize" iletemiyorum. 2) Bir LINQ sorgusu temelde bir lambda ifadesidir ve iki dizgimi bu şekilde geçiriyorum, bu yüzden bu bana bir anlam ifade etmiyor.
BlueMonkMN

3
Bir CASE-SENSITIVE veritabanında bir CASE-INSENSITIVE karşılaştırma yapmak istiyorum.
BlueMonkMN

Hangi CASE-SENSITIVE veritabanını kullanıyorsunuz?
Andrew Hare

Ayrıca, bir LINQ sorgusu lambda ifadesi değildir. LINQ sorgusu birkaç bölümden oluşur (en önemlisi sorgu işleçleri ve lambda ifadeleri).
Andrew Hare

Bu cevap BlueMonkMN yorumları kadar anlamlı değil.
Alf

0

Büyük / küçük harfe duyarlı Linq - Sql sorguları gerçekleştirmek için, aşağıdakilerden birini kullanarak sunucu veri türünü belirterek 'dize' alanlarını büyük / küçük harfe duyarlı olarak bildirin;

varchar(4000) COLLATE SQL_Latin1_General_CP1_CS_AS 

veya

nvarchar(Max) COLLATE SQL_Latin1_General_CP1_CS_AS

Not: Yukarıdaki harmanlama türlerindeki 'CS', 'Büyük / Küçük Harfe Duyarlı' anlamına gelir.

Bu, Visual Studio DBML Designer kullanarak bir özelliği görüntülerken “Sunucu Veri Türü” alanına girilebilir.

Daha fazla ayrıntı için bkz. Http://yourdotnetdesignteam.blogspot.com/2010/06/case-sensitive-linq-to-sql-queries.html


Sorun bu. Normalde kullandığım alan büyük / küçük harfe duyarlıdır (CO [karbon monoksit] kimyasal formülü Co [kobalt] 'dan farklıdır). Ancak, belirli bir durumda (arama) Co hem Co hem de CO eşleştirmek istiyorum. Farklı bir "sunucu veri türü" ile ek bir özellik tanımlamak yasal değil (linq to sql sadece sql sütun başına bir özellik izin verir). Öyleyse hala gitme.
doekman

Ayrıca, Birim Testi yapılıyorsa, bu yaklaşım büyük olasılıkla bir veri taklidi ile uyumlu olmayacaktır. Kabul edilen cevapta linq / lambda yaklaşımını kullanmak en iyisidir.
Derrick

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

1
Bunun çevrildiği SQL metni nedir ve bir SQL ortamında büyük / küçük harfe duyarlı olarak davranacak büyük / küçük harfe duyarlı olmamasına ne izin verir?
BlueMonkMN

0

Aşağıdaki 2 aşamalı yaklaşım benim için çalışıyor (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
Metin arama metniyle başlarsa bu kodda bir hata vardır (> = 0 olmalıdır)
Flatliner DOA

@FlatlinerDOA aslında olması gerektiği != -1, çünkü IndexOf "iade -1 karakter veya dize bulunmazsa"
drzaus

0

Bazen Veritabanında depolanan değer boşluk içerebilir, bu nedenle bu işlem başarısız olabilir

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

Bu sorunların çözümü, alanı kaldırmak, ardından davanın dönüştürülmesi ve bunun gibi seçilmesidir.

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

Bu durumda not

customname , Veritabanı değeriyle eşleşecek değerdir

UsersTB sınıfı

başlık Veritabanı sütunudur


-1

Sorgunun çalışıp çalışmadığı ile verimli çalışıp çalışmadığı arasında bir fark olduğunu unutmayın ! İfadenin hedefi SQL Server olduğunda bir LINQ ifadesi T-SQL'e dönüştürülür, bu nedenle üretilecek T-SQL'i düşünmeniz gerekir.

String.Equals kullanmak büyük olasılıkla (tahmin ediyorum) SQL Server tüm satırları geri getirmek ve daha sonra .NET karşılaştırması yapmak, çünkü T-SQL'ye çevrilemez bir .NET ifadesidir.

Başka bir deyişle, bir ifade kullanmak veri erişiminizi artıracak ve dizinleri kullanma yeteneğinizi kaldıracaktır. Küçük masalarda çalışacak ve farkı fark etmeyeceksiniz. Büyük bir masada çok kötü performans gösterebilir.

LINQ ile ilgili problemlerden biri bu; insanlar artık yazdıkları ifadelerin nasıl yerine getirileceğini düşünmüyorlar.

Bu durumda, bir ifade kullanmadan istediğinizi yapmanın bir yolu yoktur - T-SQL'de bile. Bu nedenle, bunu daha verimli yapamayabilirsiniz. Yukarıda verilen T-SQL yanıtı bile (harmanlama ile değişkenler kullanarak) büyük olasılıkla dizinlerin yoksayılmasıyla sonuçlanacaktır, ancak büyük bir tablo ise, ifadeyi çalıştırmaya ve bir dizinin kullanılıp kullanılmadığını görmek için yürütme planına bakmaya değer .


2
Bu doğru değil (satırların istemciye döndürülmesine neden olmaz). String.Equals kullandım ve çalışmıyor nedeni, davranış veritabanı veya sunucunun harmanlama bağlıdır bir TSQL dize karşılaştırma dönüştürülür çünkü. Ben biri için yazdığım her LINQ SQL ifadesi nasıl TSQL dönüştürülür düşünün. Ne istiyorum yolu üretilen TSQL UPPER kullanmaya zorlamak için ToUpper kullanmaktır. Daha sonra tüm dönüşüm ve karşılaştırma mantığı TSQL'de hala yapılır, böylece fazla performans kaybetmezsiniz.
BlueMonkMN
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.