LINQ contiene case insensitive


174

Questo codice fa distinzione tra maiuscole e minuscole, come renderlo maiuscole e minuscole?

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

Le risposte di Sjoerd sono corrette ma ... Voglio ottenere risultati di ricerca per nomi con un turco © (ad esempio) quando scrivo un io e viceversa. In questo caso, ToLower sembra essere la strada giusta da percorrere. Per favore correggimi se sbaglio. A proposito del turco ©: en.wikipedia.org/wiki/Dotted_and_dotless_I
He Nrik

@HeNrik - Come discusso in Turchia Test link nel commento di JYelton in risposta accettata, quando eseguito con la cultura turca, quei due i saranno diversi - quindi non troverai nomi con l'altro i. Vuoi ToLowerInvariant. Vedi la discussione sotto varie risposte qui .
ToolmakerSteve

questa è una vecchia domanda, ma vale la pena notare che nella versione attuale EF core 2.0 ToLower () funziona come segue person.Where (p => p.Name.ToLower (). Contiene (myParam.Name.ToLower () )); Sto usando questo in una query Linq contro un DB Postgres. Non ho distinzione tra maiuscole e minuscole nelle regole di confronto delle colonne nel DB e ho verificato che senza ToLower () la corrispondenza è chiaramente sensibile al maiuscolo / minuscolo.
shelbypereira,

Risposte:


72

Supponendo che stiamo lavorando con le stringhe qui, ecco un'altra soluzione "elegante" che utilizza IndexOf().

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

7
Bello. Per i miei scopi, tuttavia, questo non funziona per LINQ to Entities. Bella soluzione per LINQ to Objects però.
Damian Powell,

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

49
Come ha commentato Jon Skeet su una domanda correlata , questo metodo non supererà il Test della Turchia .
JYelton,

5
No, ma i database funzionano senza set di caratteri e regole di confronto. Se stai cercando di trasferire il lavoro al database, devi fare alcune ipotesi sul set di caratteri e sulla fascicolazione, giusto?
Christopher Stevenson,

66
Contiene dovrebbe utilizzare l' IEqualityComparer<string>attributo per gestire il funzionamento del confronto. Usa ToLower e ToUpper per verificare che l'uguaglianza sia una cattiva idea. Prova: .Contains(description, StringComparer.CurrentCultureIgnoreCase)ad esempio
Dorival

19
Il commento di @Dorival non funziona, dato che dà questo errore: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
Containscon StringComparernon riceve la stringa come parametro, quindi sarà errore di compilazione. IndexOfon Queryableprobabilmente non può essere tradotto in SQL. Personalmente ho trovato questa risposta totalmente valida mentre parliamo di LINQ nel database.
Thariq Nugrohotomo,

122

Se la query LINQ viene eseguita nel contesto del database, una chiamata a Contains()viene mappata LIKEall'operatore:

.Where(a => a.Field.Contains("hello")) diventa Field LIKE '%hello%'. L' LIKEoperatore non distingue tra maiuscole e minuscole per impostazione predefinita, ma può essere modificato modificando le regole di confronto della colonna .

Se la query LINQ viene eseguita nel contesto .NET, è possibile utilizzare IndexOf () , ma tale metodo non è supportato in LINQ to SQL.

LINQ to SQL non supporta metodi che accettano un CultureInfo come parametro, probabilmente perché non può garantire che il server SQL gestisca le colture allo stesso modo di .NET. Questo non è completamente vero, perché fa il supporto StartsWith(string, StringComparison).

Tuttavia, non sembra supportare un metodo che valuta LIKEin LINQ to SQL e un confronto senza distinzione tra maiuscole e minuscole in .NET, rendendo impossibile eseguire Contains () senza distinzione tra maiuscole e minuscole in modo coerente.


Solo FYI EF 4.3 non supporta StartsWith. Ottengo: LINQ to Entities non riconosce il metodo "Boolean StartsWith (System.String, System.StringComparison)"
nakhli

StartCon la conversione a COME 'ciao%'?
Bart Calixto,

il link clicdata è morto.
Adam Parkin,

2
grande sforzo per scavare nel comportamento generato da SQL e db per la clausola LIKE
Thariq Nugrohotomo,

1
Quindi quali sono le opzioni quando uso EF, in un contesto ho bisogno di fare insensitivericerca di casi , e nell'altro ho bisogno che sia case sensitive. Devo solo battere le prestazioni e usare 'toLower ()'?
Zapnologica,

12

La risposta accettata qui non menziona il fatto che se hai una stringa nulla ToLower () genererà un'eccezione. Il modo più sicuro sarebbe quello di fare:

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

Non è possibile generare un'eccezione su una query tradotta in SQL
Alex Zhukovskiy,

@AlexZhukovskiy Che importanza ha questo problema? Se fi.DESCRIPTION è null o la descrizione è null otterrai un'eccezione di riferimento null C #. Non importa in cosa converte la query LINQ sul lato SQL. Ecco la prova: dotnetfiddle.net/5pZ1dY
Marko

Perché questa query non riuscirà la traduzione in SQL perché non supporta l'operatore null coaleshing. E probabilmente stai interrogando il database invece di caricare tutte le voci per utilizzare la coalescenza nulla sul lato client. Quindi, se lo usi, va bene sul lato client ma fallisce sul DB, altrimenti stai bene con DB e non ti importa di nullref sul lato client perché non accadrà perché C # non esegue questa query e non lo fa effettivamente leggere oggetti null.
Alex Zhukovskiy,

Questa risposta mi ha aiutato a risolvere un problema che stavo ottenendo su LINQ alle entità in cui stavo facendo .IndexOf e .Contains su un IEnumerable in cui il valore della stringa proveniente dal database era nullo. Non ho ricevuto l'errore fino a quando non è stato elencato il risultato e quindi ho ricevuto un messaggio di errore che "Il riferimento all'oggetto non è impostato su un'istanza di un oggetto". Non riuscivo a capire perché fosse successo fino a quando non ho visto questo post. Grazie!
randyh22,

7

Utilizzando C # 6.0 (che consente le funzioni di espressione e la propagazione nulla), per LINQ to Objects, può essere fatto in una sola riga come questa (controllando anche la presenza di null):

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

Non funziona perché ContainsInsensitive non è un comando store
Sven

@Sven - sì, funziona solo per LINQ to Objects. Ho corretto la mia risposta. Grazie.
Alexei,

4

IndexOf funziona meglio in questo caso

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

3

Puoi usare string.Compare

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

se vuoi solo controllare contiene quindi usa "Qualsiasi"

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

Questo non risponde alla domanda. L'OP chiede "Contiene" all'interno di una stringa (ovvero, una stringa ne contiene un'altra), non se una raccolta di stringhe contiene una singola stringa.
Andrewf

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

2
possiamo usare metodi di estensione personalizzati nelle query linq? sei sicuro ?
Vishal Sharma,


0

Onestamente, questo non deve essere difficile. Può sembrare che all'inizio, ma non lo è. Ecco una semplice query linq in C # che fa esattamente come richiesto.

Nel mio esempio, sto lavorando su un elenco di persone che hanno una proprietà chiamata FirstName.

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

Ciò cercherà nel database con la ricerca in minuscolo ma restituirà i risultati in maiuscolo.


-2

Usa il metodo String.Equals

public IQueryable<FACILITY_ITEM> GetFacilityItemRootByDescription(string description)
{
    return this.ObjectContext.FACILITY_ITEM
           .Where(fi => fi.DESCRIPTION
           .Equals(description, StringComparison.OrdinalIgnoreCase));
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.