LINQ มีตัวพิมพ์เล็กและตัวพิมพ์ใหญ่


174

รหัสนี้เป็นแบบตรงตามตัวพิมพ์เล็กและใหญ่

public IQueryable<FACILITY_ITEM> GetFacilityItemRootByDescription(string description)
{
    return this.ObjectContext.FACILITY_ITEM.Where(fi => fi.DESCRIPTION.Contains(description));
}

คำตอบของ Sjoerd นั้นถูกต้อง แต่ ... ฉันต้องการได้ผลลัพธ์การค้นหาชื่อที่มีภาษาตุรกีİ (ตัวอย่าง) เมื่อเขียน i และในทางกลับกัน ในกรณีนี้ ToLower น่าจะเป็นวิธีที่ถูกต้อง โปรดแก้ไขฉันหากฉันผิด เกี่ยวกับตุรกีİ: en.wikipedia.org/wiki/Dotted_and_dotless_I
He Nrik

@HeNrik - ตามที่กล่าวไว้ในลิงค์ทดสอบตุรกีในความคิดเห็นของ JYelton ภายใต้คำตอบที่ยอมรับเมื่อทำงานกับวัฒนธรรมตุรกีทั้งสองของฉันจะแตกต่างกันดังนั้นคุณจะไม่พบชื่อกับอีกคนหนึ่ง คุณต้องการ ToLowerInvariant ดูการอภิปรายภายใต้คำตอบต่างๆที่นี่
ToolmakerSteve

นี่เป็นคำถามเก่า แต่ควรทราบว่าในเวอร์ชันปัจจุบัน EF core 2.0 ToLower () ทำงานตาม person.Where (p => p.Name.ToLower () ประกอบด้วย (myParam.Name.ToLower () )); ฉันใช้สิ่งนี้ในการสืบค้น Linq กับฐานข้อมูล Postgres ฉันไม่มี case insensitivty ในการจัดเรียงคอลัมน์ในฐานข้อมูลและฉันตรวจสอบว่าไม่มี ToLower () การจับคู่นั้นคำนึงถึงขนาดตัวพิมพ์อย่างชัดเจน
shelbypereira

คำตอบ:


72

สมมติว่าเรากำลังทำงานกับสตริงที่นี่นี่เป็นอีกวิธีที่ "สง่างาม" IndexOf()โดยใช้

public IQueryable<FACILITY_ITEM> GetFacilityItemRootByDescription(string description)
{
    return this.ObjectContext.FACILITY_ITEM
        .Where(fi => fi.DESCRIPTION
                       .IndexOf(description, StringComparison.OrdinalIgnoreCase) != -1);
}

7
ดี เพื่อจุดประสงค์ของฉันเองสิ่งนี้ไม่ได้ผลสำหรับ LINQ to Entities ทางออกที่ดีสำหรับ LINQ ไปยังวัตถุแม้ว่า
เดเมียนพาวเวล

242
fi => fi.DESCRIPTION.ToLower().Contains(description.ToLower())

49
ในฐานะที่เป็นจอนสกีตแสดงความคิดเห็นในคำถามที่เกี่ยวข้องวิธีการนี้จะไม่ผ่านการทดสอบตุรกี
JYelton

5
ไม่ แต่ฐานข้อมูลจะทำงานจากชุดอักขระและการเปรียบเทียบ หากคุณพยายามผลักดันงานไปยังฐานข้อมูลคุณต้องตั้งสมมติฐานเกี่ยวกับชุดอักขระและการเรียงตัวใช่มั้ย
Christopher Stevenson

66
ควรจะมีการใช้IEqualityComparer<string>คุณลักษณะเพื่อจัดการกับการเปรียบเทียบจะทำงานอย่างไร ใช้ ToLower และ ToUpper เพื่อตรวจสอบความเท่าเทียมกันเป็นความคิดที่ไม่ดี ลอง: .Contains(description, StringComparer.CurrentCultureIgnoreCase)ตัวอย่างเช่น
Dorival

19
ความคิดเห็นจาก @Dorival ใช้งานไม่ได้เพราะมันให้ข้อความผิดพลาดนี้: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
Containsด้วยStringComparerไม่ได้รับสตริงเป็นพารามิเตอร์ดังนั้นมันจะเป็น build-error IndexOfบนQueryableอาจไม่สามารถแปลเป็น SQL โดยส่วนตัวแล้วฉันพบว่าคำตอบนี้ใช้ได้อย่างสมบูรณ์ในขณะที่เราพูดถึง LINQ กับฐานข้อมูล
Thariq Nugrohotomo

122

หากการสืบค้น LINQ ถูกดำเนินการในบริบทฐานข้อมูลการเรียกไปที่จะContains()ถูกแมปไปยังLIKEผู้ประกอบการ:

.Where(a => a.Field.Contains("hello"))Field LIKE '%hello%'จะกลายเป็น LIKEผู้ประกอบการเป็นกรณีตายตามค่าเริ่มต้น แต่ที่สามารถเปลี่ยนแปลงได้โดยเปลี่ยนการเปรียบเทียบของคอลัมน์

หากดำเนินการสืบค้น LINQ ในบริบท. NET คุณสามารถใช้IndexOf ()ได้ แต่วิธีดังกล่าวไม่ได้รับการสนับสนุนใน LINQ ไปยัง SQL

LINQ to SQL ไม่สนับสนุนวิธีการที่ใช้ CultureInfo เป็นพารามิเตอร์อาจเป็นเพราะไม่สามารถรับประกันได้ว่าเซิร์ฟเวอร์ SQL จะจัดการกับวัฒนธรรมแบบเดียวกันกับ. NET นี้ไม่เป็นความจริงอย่างสิ้นเชิงเพราะมันไม่StartsWith(string, StringComparison)สนับสนุน

อย่างไรก็ตามดูเหมือนจะไม่สนับสนุนวิธีการประเมินLIKEใน LINQ กับ SQL และการเปรียบเทียบแบบ insensitive ของ case ใน. NET ทำให้เป็นไปไม่ได้ที่จะทำ case insensitive ประกอบด้วย () ในวิธีที่สอดคล้องกัน


เพียงแค่ FYI EF 4.3 ไม่รองรับ StartsWith ฉันได้รับ: LINQ to Entities ไม่รู้จักวิธี 'Boolean StartsWith (System.String, System.StringComparison)'
nakhli

Start เมื่อแปลงเป็น LIKE 'hello%' หรือไม่
บาร์ต Calixto

ลิงก์ clicdata นั้นตายแล้ว
Adam Parkin

2
ความพยายามอย่างมากสำหรับการขุดลงใน SQL และ db ที่สร้างขึ้นสำหรับพฤติกรรม LIKE clause
Thariq Nugrohotomo

1
ดังนั้นสิ่งที่เป็นตัวเลือกคนเมื่อใช้ EF ในบริบทหนึ่งที่ฉันต้องทำกรณีinsensitiveค้นหาและอื่น ๆ case sensitiveที่ผมต้องการให้เป็น ฉันต้องใช้ประสิทธิภาพในการเคาะและใช้ 'toLower ()' หรือไม่
Zapnologica

12

คำตอบที่ยอมรับที่นี่ไม่ได้กล่าวถึงความจริงที่ว่าถ้าคุณมีสตริงที่ว่าง ToLower () จะโยนข้อยกเว้น วิธีที่ปลอดภัยกว่าคือ:

fi => (fi.DESCRIPTION ?? string.Empty).ToLower().Contains((description ?? string.Empty).ToLower())

คุณไม่สามารถสร้างข้อยกเว้นในแบบสอบถามที่แปลเป็น SQL
Alex Zhukovskiy

@AlexZhukovskiy เป็นยังไงบ้างที่เกี่ยวข้องกับปัญหานี้? ถ้า fi.DESCRIPTION เป็นโมฆะหรือคำอธิบายเป็นโมฆะคุณจะได้รับข้อยกเว้นอ้างอิง C # null มันไม่สำคัญว่าแบบสอบถาม LINQ จะแปลงไปเป็นอะไรใน SQL นี่คือข้อพิสูจน์: dotnetfiddle.net/5pZ1dY
Marko

เพราะแบบสอบถามนี้จะล้มเหลวในการแปลเป็น SQL เพราะมันไม่รองรับตัวดำเนินการรวมศูนย์ และคุณอาจจะสอบถามฐานข้อมูลแทนที่จะโหลดรายการทั้งหมดเพื่อใช้ null รวมตัวกันบนฝั่งไคลเอ็นต์ ดังนั้นถ้าคุณใช้มัน - มันใช้ได้ในฝั่งไคลเอ็นต์ แต่ล้มเหลวใน DB มิฉะนั้นคุณก็ใช้ได้กับ DB และคุณไม่สนใจ nullref ในฝั่งไคลเอ็นต์เพราะมันจะไม่เกิดขึ้นเพราะ C # ไม่ได้เรียกใช้แบบสอบถามนี้และไม่ ไม่ได้อ่านวัตถุว่างเปล่า
Alex Zhukovskiy

คำตอบนี้ช่วยฉันแก้ปัญหาที่ฉันได้รับใน LINQ ไปยังหน่วยงานที่ฉันทำ. ดัชนีและ. อยู่ใน IEnumerable ที่ค่าสตริงมาจากฐานข้อมูลเป็นโมฆะ ฉันไม่ได้รับข้อผิดพลาดจนกว่าผลลัพธ์จะถูกระบุและฉันได้รับข้อความแสดงข้อผิดพลาดว่า "การอ้างอิงวัตถุไม่ได้ถูกตั้งค่าเป็นอินสแตนซ์ของวัตถุ" ฉันไม่ทราบสาเหตุที่เกิดขึ้นจนกว่าฉันจะเห็นโพสต์นี้ ขอบคุณ!
randyh22

7

การใช้ C # 6.0 (ซึ่งอนุญาตให้ใช้ฟังก์ชั่นการแสดงออกของร่างกายและการเผยแพร่ null) สำหรับ LINQ ไปยังวัตถุสามารถทำได้ในบรรทัดเดียวเช่นนี้ (ตรวจสอบ null)

public static bool ContainsInsensitive(this string str, string value) => str?.IndexOf(value, StringComparison.OrdinalIgnoreCase) >= 0;

มันไม่ทำงานเพราะมีความสำคัญไม่ได้เป็นคำสั่งร้านค้า
สเวน

@Sven - ใช่มันใช้งานได้กับ LINQ ไปยัง Objects เท่านั้น ฉันได้แก้ไขคำตอบแล้ว ขอบคุณ
Alexei

4

IndexOf ทำงานได้ดีที่สุดในกรณีนี้

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

3

คุณสามารถใช้สตริงเปรียบเทียบ

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

หากคุณเพียงต้องการตรวจสอบว่ามีแล้วใช้ "ใด ๆ "

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

สิ่งนี้ไม่ตอบคำถาม OP กำลังถามเกี่ยวกับ 'มี' ภายในสตริง (เช่นหนึ่งสตริงมีอีกอัน) ไม่ว่าจะเป็นชุดของสตริงที่มีสตริงเดียว
andrewf

1
public static bool Contains(this string input, string findMe, StringComparison comparisonType)
{
    return String.IsNullOrWhiteSpace(input) ? false : input.IndexOf(findMe, comparisonType) > -1;
}

2
เราสามารถใช้วิธีการขยายแบบกำหนดเองในการสืบค้น linq ได้ไหม คุณแน่ใจไหม ?
Vishal Sharma


0

สุจริตไม่จำเป็นต้องเป็นเรื่องยาก อาจดูเหมือนว่าในการโจมตี แต่มันไม่ได้ ต่อไปนี้เป็นเคียวรี linq แบบง่าย ๆ ใน C # ที่ทำงานได้ตรงตามที่ร้องขอ

ในตัวอย่างของฉันฉันกำลังทำงานกับรายชื่อบุคคลที่มีคุณสมบัติหนึ่งชื่อ FirstName

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

การทำเช่นนี้จะค้นหาฐานข้อมูลด้วยการค้นหาตัวพิมพ์เล็ก แต่กลับผลลัพธ์ของตัวพิมพ์ใหญ่ทั้งหมด


-2

ใช้วิธีการString.Equals

public IQueryable<FACILITY_ITEM> GetFacilityItemRootByDescription(string description)
{
    return this.ObjectContext.FACILITY_ITEM
           .Where(fi => fi.DESCRIPTION
           .Equals(description, StringComparison.OrdinalIgnoreCase));
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.