LINQ enthält Groß- und Kleinschreibung

174

Bei diesem Code wird zwischen Groß- und Kleinschreibung unterschieden. Wie wird die Groß- und Kleinschreibung beachtet?

public IQueryable<FACILITY_ITEM> GetFacilityItemRootByDescription(string description)
{
    return this.ObjectContext.FACILITY_ITEM.Where(fi => fi.DESCRIPTION.Contains(description));
}
Jeaf Gilbert
quelle
Sjoerds Antworten sind richtig, aber ... Ich möchte Suchergebnisse für Namen mit einem türkischen İ (zum Beispiel) erhalten, wenn ich ein i schreibe und umgekehrt. In diesem Fall scheint ToLower der richtige Weg zu sein. Bitte korrigieren Sie mich, wenn ich falsch liege. Über türkisch İ: en.wikipedia.org/wiki/Dotted_and_dotless_I
He Nrik
@HeNrik - Wie im Türkei-Testlink in JYeltons Kommentar unter akzeptierter Antwort besprochen, werden diese beiden Ichs unterschiedlich sein, wenn sie mit der türkischen Kultur betrieben werden - so dass Sie keine Namen mit dem anderen Ich finden. Sie möchten ToLowerInvariant. Siehe Diskussion unter verschiedenen Antworten hier .
ToolmakerSteve
Dies ist eine alte Frage, aber es ist erwähnenswert, dass in der aktuellen Version EF Core 2.0 ToLower () wie folgt funktioniert: person.Where (p => p.Name.ToLower (). Contains (myParam.Name.ToLower () )); Ich verwende dies in einer Linq-Abfrage für eine Postgres-Datenbank. Ich habe keine Groß- und Kleinschreibung bei der Spaltenkollatierung in der Datenbank und habe überprüft, dass bei ToLower () die Übereinstimmung eindeutig zwischen Groß- und Kleinschreibung unterscheidet.
Shelbypereira

Antworten:

72

Angenommen, wir arbeiten hier mit Strings, dann ist hier eine andere "elegante" Lösung IndexOf().

public IQueryable<FACILITY_ITEM> GetFacilityItemRootByDescription(string description)
{
    return this.ObjectContext.FACILITY_ITEM
        .Where(fi => fi.DESCRIPTION
                       .IndexOf(description, StringComparison.OrdinalIgnoreCase) != -1);
}
Jeff Mercado
quelle
7
Nett. Für meine eigenen Zwecke funktioniert dies jedoch nicht für LINQ to Entities. Gute Lösung für LINQ to Objects.
Damian Powell
242
fi => fi.DESCRIPTION.ToLower().Contains(description.ToLower())
Nealv
quelle
49
Wie Jon Skeet zu einer verwandten Frage kommentierte , wird diese Methode den Türkei-Test nicht bestehen .
JYelton
5
Nein, aber Datenbanken arbeiten mit Zeichensätzen und Sortierungen. Wenn Sie versuchen, die Arbeit in die Datenbank zu verschieben, müssen Sie einige Annahmen über Zeichensatz und Sortierung treffen, oder?
Christopher Stevenson
66
Enthält sollte ein IEqualityComparer<string>Attribut verwenden, um zu handhaben, wie der Vergleich funktioniert. Verwenden Sie ToLower und ToUpper, um die Gleichheit zu überprüfen. Dies ist eine schlechte Idee. Versuchen Sie: .Contains(description, StringComparer.CurrentCultureIgnoreCase)zum Beispiel
Dorival
19
Der Kommentar von @Dorival funktioniert nicht, da er diese Fehlermeldung enthält: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
Containswith StringComparererhält keine Zeichenfolge als Parameter, daher handelt es sich um einen Build-Fehler. IndexOfon Queryablekann wahrscheinlich nicht in SQL übersetzt werden. Persönlich fand ich diese Antwort absolut gültig, da wir über LINQ to Database sprechen.
Thariq Nugrohotomo
122

Wenn die LINQ-Abfrage im Datenbankkontext ausgeführt Contains()wird, wird dem LIKEOperator ein Aufruf von zugeordnet :

.Where(a => a.Field.Contains("hello")) wird Field LIKE '%hello%'. Der LIKEOperator unterscheidet standardmäßig nicht zwischen Groß- und Kleinschreibung. Dies kann jedoch durch Ändern der Sortierung der Spalte geändert werden .

Wenn die LINQ-Abfrage im .NET-Kontext ausgeführt wird, können Sie IndexOf () verwenden , diese Methode wird jedoch in LINQ to SQL nicht unterstützt.

LINQ to SQL unterstützt keine Methoden , die CultureInfo als Parameter verwenden, wahrscheinlich weil nicht garantiert werden kann, dass der SQL Server Kulturen wie .NET behandelt. Das ist nicht ganz richtig, denn es tut Unterstützung StartsWith(string, StringComparison).

Es scheint jedoch keine Methode zu unterstützen, die LIKEin LINQ zu SQL und zu einem Vergleich ohne Berücksichtigung der Groß- und Kleinschreibung in .NET ausgewertet wird , sodass es unmöglich ist, Contains () ohne Berücksichtigung der Groß- und Kleinschreibung auf konsistente Weise auszuführen.

Sjoerd
quelle
Nur FYI EF 4.3 unterstützt StartsWith nicht. Ich bekomme: LINQ to Entities erkennt die Methode 'Boolean StartsWith (System.String, System.StringComparison)' nicht
Nakhli
StartWith konvertiert zu LIKE 'Hallo%'?
Bart Calixto
clicdata link ist tot.
Adam Parkin
2
großer Aufwand für die Untersuchung des generierten SQL- und DB-Verhaltens für die LIKE-Klausel
Thariq Nugrohotomo
1
Also, was sind die Optionen bei der Verwendung von EF? In einem Kontext muss ich eine insensitiveFallsuche durchführen, und in dem anderen muss es sein case sensitive. Muss ich nur den Performance-Knock nehmen und 'toLower ()' verwenden?
Zapnologica
12

In der hier akzeptierten Antwort wird nicht erwähnt, dass ToLower () eine Ausnahme auslöst, wenn Sie eine Nullzeichenfolge haben. Der sicherere Weg wäre:

fi => (fi.DESCRIPTION ?? string.Empty).ToLower().Contains((description ?? string.Empty).ToLower())
Marko
quelle
Sie können keine Ausnahme für eine in SQL übersetzte Abfrage generieren
Alex Zhukovskiy
@AlexZhukovskiy Wie ist das überhaupt für dieses Problem relevant? Wenn fi.DESCRIPTION null oder description null ist, wird eine C # null-Referenzausnahme angezeigt. Es spielt keine Rolle, in was die LINQ-Abfrage auf der SQL-Seite konvertiert wird. Hier ist der Beweis: dotnetfiddle.net/5pZ1dY
Marko
Da diese Abfrage bei der Übersetzung in SQL fehlschlägt, weil sie keinen Null-Coaleshing-Operator unterstützt. Und Sie fragen wahrscheinlich die Datenbank ab, anstatt alle Einträge zu laden, um auf der Clientseite Null-Coaleshing zu verwenden. Wenn Sie es also verwenden, ist es auf der Clientseite in Ordnung, schlägt jedoch auf der Datenbank fehl, andernfalls ist die Datenbank in Ordnung und Sie kümmern sich nicht um nullref auf der Clientseite, da dies nicht der Fall ist, da C # diese Abfrage nicht ausführt und dies nicht tut Lesen Sie tatsächlich keine Nullobjekte.
Alex Zhukovskiy
Diese Antwort hat mir geholfen, ein Problem zu lösen, das ich bei LINQ to Entities hatte, wo ich .IndexOf und .Contains auf einem IEnumerable ausgeführt habe, bei dem der aus der Datenbank stammende Zeichenfolgenwert null war. Ich habe den Fehler erst erhalten, als das Ergebnis aufgelistet wurde, und dann die Fehlermeldung "Objektreferenz nicht auf eine Instanz eines Objekts festgelegt" erhalten. Ich konnte nicht herausfinden, warum es passierte, bis ich diesen Beitrag sah. Vielen Dank!
Randyh22
7

Mit C # 6.0 (das Ausdrucksfunktionen und die Weitergabe von Nullen ermöglicht) kann LINQ to Objects in einer einzigen Zeile wie dieser ausgeführt werden (auch auf Null prüfen):

public static bool ContainsInsensitive(this string str, string value) => str?.IndexOf(value, StringComparison.OrdinalIgnoreCase) >= 0;
Alexei
quelle
Es funktioniert nicht, weil ContainsInsensitive kein Speicherbefehl ist
Sven
@Sven - ja, es funktioniert nur für LINQ to Objects. Ich habe meine Antwort korrigiert. Vielen Dank.
Alexei
4

IndexOf funktioniert in diesem Fall am besten

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

Sie können string.Compare verwenden

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

Wenn Sie nur die enthaltenen Inhalte überprüfen möchten, verwenden Sie "Beliebig".

  lst.Any(x => string.Compare(x,"valueToCompare",StringComparison.InvariantCultureIgnoreCase)==0)
Code zuerst
quelle
Dies beantwortet die Frage nicht. Das OP fragt nach 'Enthält' innerhalb einer Zeichenfolge (dh eine Zeichenfolge enthält eine andere) und nicht, ob eine Sammlung von Zeichenfolgen eine einzelne Zeichenfolge enthält.
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
quelle
2
Können wir benutzerdefinierte Erweiterungsmethoden in Linq-Abfragen verwenden? bist du sicher ?
Vishal Sharma
0

Ehrlich gesagt muss das nicht schwierig sein. Es mag so scheinen, als ob es am Anfang wäre, aber es ist nicht so. Hier ist eine einfache Linq-Abfrage in C #, die genau den Anforderungen entspricht.

In meinem Beispiel arbeite ich gegen eine Liste von Personen mit einer Eigenschaft namens Vorname.

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

Dadurch wird die Datenbank bei der Suche in Kleinbuchstaben durchsucht, es werden jedoch vollständige Ergebnisse in Groß- und Kleinschreibung zurückgegeben.

Frank Thomas
quelle
-2

Verwenden Sie die String.Equals- Methode

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