LINQ Berisi Tidak Peka Huruf

174

Kode ini peka terhadap huruf besar-kecil, bagaimana membuatnya tidak peka huruf besar kecil?

public IQueryable<FACILITY_ITEM> GetFacilityItemRootByDescription(string description)
{
    return this.ObjectContext.FACILITY_ITEM.Where(fi => fi.DESCRIPTION.Contains(description));
}
Jeaf Gilbert
sumber
Jawaban Sjoerd benar tetapi ... Saya ingin mendapatkan hasil pencarian untuk nama-nama dengan Turki İ (misalnya) saat menulis i dan sebaliknya. Dalam hal ini ToLower tampaknya merupakan cara yang benar untuk dilakukan. Harap perbaiki saya jika saya salah. Tentang turki İ: en.wikipedia.org/wiki/Dotted_and_dotless_I
He Nrik
@HeNrik - Seperti yang dibahas dalam tautan Uji Turki dalam komentar JYelton di bawah jawaban yang diterima, ketika dijalankan dengan budaya Turki, kedua aku akan berbeda - sehingga Anda tidak akan menemukan nama dengan yang lain saya. Anda ingin ToLowerInvariant. Lihat diskusi di bawah berbagai jawaban di sini .
ToolmakerSteve
ini adalah pertanyaan lama, tetapi perlu dicatat bahwa dalam versi saat ini EF core 2.0 ToLower () berfungsi sebagai berikut. Di mana (p => p.Name.ToLower (). Berisi (myParam.Name.ToLower () )); Saya menggunakan ini dalam permintaan Linq terhadap DB Postgres. Saya tidak memiliki case insensitivty pada susunan kolom di DB dan saya memeriksa bahwa tanpa ToLower () pertandingan jelas case-sensitive.
shelbypereira

Jawaban:

72

Dengan asumsi kami bekerja dengan string di sini, berikut ini adalah solusi "elegan" lainnya yang digunakan IndexOf().

public IQueryable<FACILITY_ITEM> GetFacilityItemRootByDescription(string description)
{
    return this.ObjectContext.FACILITY_ITEM
        .Where(fi => fi.DESCRIPTION
                       .IndexOf(description, StringComparison.OrdinalIgnoreCase) != -1);
}
Jeff Mercado
sumber
7
Bagus. Untuk tujuan saya sendiri, ini tidak berfungsi untuk LINQ untuk Entitas. Solusi yang bagus untuk LINQ to Objects sekalipun.
Damian Powell
242
fi => fi.DESCRIPTION.ToLower().Contains(description.ToLower())
Nealv
sumber
49
Ketika Jon Skeet mengomentari pertanyaan terkait , metode ini tidak akan lulus Tes Turki .
JYelton
5
Tidak, tetapi basis data berfungsi dari kumpulan karakter dan susunan. Jika Anda mencoba untuk mengalihkan pekerjaan ke database, Anda harus membuat beberapa asumsi tentang set karakter dan susunan, kan?
Christopher Stevenson
66
Berisi harus menggunakan IEqualityComparer<string>atribut untuk menangani bagaimana perbandingan akan bekerja. Menggunakan ToLower dan ToUpper untuk memeriksa kesetaraan adalah ide yang buruk. Coba: .Contains(description, StringComparer.CurrentCultureIgnoreCase)misalnya
Dorival
19
Komentar dari @Dorival tidak berfungsi, karena ini memberikan errormessage ini:Error 1 'string' does not contain a definition for 'Contains' and the best extension method overload 'System.Linq.ParallelEnumerable.Contains<TSource>(System.Linq.ParallelQuery<TSource>, TSource, System.Collections.Generic.IEqualityComparer<TSource>)' has some invalid arguments
emi
6
Containsdengan StringComparertidak menerima string sebagai parameter, jadi itu akan menjadi kesalahan build. IndexOfpada Queryablemungkin tidak dapat diterjemahkan ke dalam SQL. Secara pribadi saya menemukan jawaban ini benar-benar valid ketika kita berbicara tentang LINQ ke basis data.
Thariq Nugrohotomo
122

Jika kueri LINQ dieksekusi dalam konteks basis data, panggilan ke Contains()dipetakan ke LIKEoperator:

.Where(a => a.Field.Contains("hello")) menjadi Field LIKE '%hello%'. The LIKEoperator adalah kasus sensitif secara default, tapi itu dapat diubah dengan mengubah pengumpulan kolom .

Jika kueri LINQ dieksekusi dalam konteks .NET, Anda bisa menggunakan IndexOf () , tetapi metode itu tidak didukung di LINQ ke SQL.

LINQ to SQL tidak mendukung metode yang menggunakan CultureInfo sebagai parameter, mungkin karena tidak dapat menjamin bahwa SQL server menangani budaya yang sama dengan .NET. Ini tidak sepenuhnya benar, karena memang mendukung StartsWith(string, StringComparison).

Namun, tampaknya tidak mendukung metode yang mengevaluasi LIKEdalam LINQ ke SQL, dan perbandingan kasus yang tidak sensitif dalam.

Sjoerd
sumber
Just FYI EF 4.3 tidak mendukung StartsWith. Saya mendapatkan: LINQ to Entities tidak mengenali metode 'Boolean StartsWith (System.String, System.StringComparison)'
nakhli
MulaiDengan mengkonversi menjadi LIKE 'hello%'?
Bart Calixto
tautan clicdata sudah mati.
Adam Parkin
2
usaha keras untuk menggali perilaku SQL dan db yang dihasilkan untuk klausa LIKE
Thariq Nugrohotomo
1
Jadi pilihan apa yang digunakan ketika menggunakan EF, Dalam satu konteks saya perlu melakukan insensitivepencarian kasus , dan dalam yang lain saya membutuhkannya case sensitive. Apakah saya hanya perlu mengetuk kinerja dan menggunakan 'toLower ()'?
Zapnologica
12

Jawaban yang diterima di sini tidak menyebutkan fakta bahwa jika Anda memiliki string null ToLower () akan melempar pengecualian. Cara yang lebih aman adalah dengan melakukan:

fi => (fi.DESCRIPTION ?? string.Empty).ToLower().Contains((description ?? string.Empty).ToLower())
Marko
sumber
Anda tidak dapat membuat pengecualian pada permintaan yang diterjemahkan ke SQL
Alex Zhukovskiy
@AlexZhukovskiy Bagaimana itu relevan dengan masalah ini? Jika fi.DESCRIPTION adalah nol atau deskripsi adalah nol Anda mendapatkan pengecualian referensi C # null. Tidak peduli apa yang dikonversi oleh query LINQ di sisi SQL. Inilah buktinya: dotnetfiddle.net/5pZ1dY
Marko
Karena permintaan ini akan gagal menerjemahkan ke SQL karena tidak mendukung operator null coaleshing. Dan Anda mungkin mem-query database bukannya memuat semua entri untuk menggunakan null coaleshing di sisi klien. Jadi jika Anda menggunakannya - tidak apa-apa di sisi klien tetapi gagal pada DB, jika tidak, Anda baik-baik saja dengan DB dan Anda tidak peduli tentang nullref di sisi klien karena itu tidak akan terjadi karena C # tidak menjalankan kueri ini dan tidak sebenarnya membaca objek nol.
Alex Zhukovskiy
Jawaban ini membantu saya memecahkan masalah yang saya dapatkan di LINQ ke Entitas tempat saya mengerjakan .IndexOf dan .Berisi tentang IEnumerable di mana nilai string yang berasal dari database adalah nol. Saya tidak mendapatkan kesalahan sampai hasilnya disebutkan dan kemudian saya mendapat pesan kesalahan bahwa "Referensi objek tidak disetel ke instance objek." Saya tidak tahu mengapa itu terjadi sampai saya melihat posting ini. Terima kasih!
randyh22
7

Menggunakan C # 6.0 (yang memungkinkan fungsi ekspresi tubuh dan propagasi nol), untuk LINQ ke Objek, dapat dilakukan dalam satu baris seperti ini (juga memeriksa nol):

public static bool ContainsInsensitive(this string str, string value) => str?.IndexOf(value, StringComparison.OrdinalIgnoreCase) >= 0;
Alexei
sumber
Ini tidak berfungsi karena ContainsInsensitive bukan perintah toko
Sven
@Ven - ya, itu hanya berfungsi untuk LINQ ke Objects. Saya telah memperbaiki jawaban saya. Terima kasih.
Alexei
4

IndexOf bekerja paling baik dalam hal ini

return this
   .ObjectContext
   .FACILITY_ITEM
   .Where(fi => fi.DESCRIPTION.IndexOf(description, StringComparison.OrdinalIgnoreCase)>=0);
Menelaos Vergis
sumber
3

Anda dapat menggunakan string. Bandingkan

    lst.Where(x => string.Compare(x,"valueToCompare",StringComparison.InvariantCultureIgnoreCase)==0);

jika Anda hanya ingin memeriksa isi maka gunakan "Apa"

  lst.Any(x => string.Compare(x,"valueToCompare",StringComparison.InvariantCultureIgnoreCase)==0)
Kode Pertama
sumber
Ini tidak menjawab pertanyaan. OP bertanya tentang 'Berisi' dalam suatu string (yaitu, satu string berisi lainnya), bukan apakah kumpulan string berisi string tunggal.
andrewf
1
public static bool Contains(this string input, string findMe, StringComparison comparisonType)
{
    return String.IsNullOrWhiteSpace(input) ? false : input.IndexOf(findMe, comparisonType) > -1;
}
E Rolnicki
sumber
2
dapatkah kita menggunakan metode ekstensi khusus dalam kueri linq? apakah kamu yakin
Vishal Sharma
0

Jujur, ini tidak harus sulit. Mungkin terlihat bahwa pada permulaan, tetapi tidak. Inilah kueri linq sederhana dalam C # yang melakukan persis seperti yang diminta.

Dalam contoh saya, saya bekerja melawan daftar orang yang memiliki satu properti bernama FirstName.

var results = ClientsRepository().Where(c => c.FirstName.ToLower().Contains(searchText.ToLower())).ToList();

Ini akan mencari database pada pencarian huruf kecil tetapi mengembalikan hasil huruf penuh.

Frank Thomas
sumber
-2

Gunakan Metode String.Equals

public IQueryable<FACILITY_ITEM> GetFacilityItemRootByDescription(string description)
{
    return this.ObjectContext.FACILITY_ITEM
           .Where(fi => fi.DESCRIPTION
           .Equals(description, StringComparison.OrdinalIgnoreCase));
}
Francesco Moroni
sumber