LINQ contém maiúsculas e minúsculas


174

Este código faz distinção entre maiúsculas e minúsculas, como torná-lo sem distinção entre maiúsculas e minúsculas?

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

As respostas de Sjoerd estão corretas, mas ... Desejo obter resultados de pesquisa de nomes com um turco © (por exemplo) ao escrever um ie vice-versa. Nesse caso, ToLower parece ser o caminho correto a seguir. Por favor me corrija se eu estiver errado. Sobre turco ©: en.wikipedia.org/wiki/Dotted_and_dotless_I
He Nrik

@HeNrik - Conforme discutido no link Teste da Turquia no comentário de JYelton sob resposta aceita, quando executado com a cultura turca, esses dois i serão diferentes - para que você não encontre nomes com o outro i. Você deseja ToLowerInvariant. Veja a discussão sob várias respostas aqui .
Home

essa é uma pergunta antiga, mas vale a pena notar que, na versão atual, o EF core 2.0 ToLower () funciona da seguinte maneira: person.Where (p => p.Name.ToLower (). Contains (myParam.Name.ToLower ()) )); Eu estou usando isso em uma consulta Linq contra um banco de dados Postgres. Não tenho insensibilidade a maiúsculas e minúsculas no agrupamento de colunas no banco de dados e verifiquei que sem ToLower () a correspondência é claramente sensível a maiúsculas e minúsculas.
Shelbypereira 26/09/19

Respostas:


72

Supondo que estamos trabalhando com strings aqui, aqui está outra solução "elegante" usando IndexOf().

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

7
Agradável. Para meus próprios fins, porém, isso não funciona para o LINQ to Entities. Solução agradável para o LINQ to Objects.
Damian Powell

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

49
Como Jon Skeet comentou sobre uma questão relacionada , esse método não será aprovado no Teste da Turquia .
JYelton

5
Não, mas os bancos de dados funcionam com conjuntos de caracteres e agrupamento. Se você está tentando enviar trabalho para o banco de dados, precisa fazer algumas suposições sobre conjunto de caracteres e agrupamento, certo?
Christopher Stevenson

66
Contém deve estar usando o IEqualityComparer<string>atributo para manipular como a comparação funcionará. Use ToLower e ToUpper para verificar a igualdade é uma má idéia. Tente: .Contains(description, StringComparer.CurrentCultureIgnoreCase)por exemplo
Dorival

19
O comentário de @Dorival não funciona, pois fornece esta mensagem de erro: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 StringComparernão recebe string como parâmetro, portanto, haverá erro de construção. IndexOfem Queryable, provavelmente, não pode ser traduzido em SQL. Pessoalmente, achei essa resposta totalmente válida quando falamos sobre LINQ to database.
Thariq Nugrohotomo 10/04/2015

122

Se a consulta LINQ for executada no contexto do banco de dados, uma chamada para Contains()será mapeada para o LIKEoperador:

.Where(a => a.Field.Contains("hello")) torna-se Field LIKE '%hello%'. O LIKEoperador não diferencia maiúsculas de minúsculas por padrão, mas isso pode ser alterado alterando o agrupamento da coluna .

Se a consulta LINQ for executada no contexto .NET, você poderá usar IndexOf () , mas esse método não é suportado no LINQ to SQL.

O LINQ to SQL não oferece suporte a métodos que usam um CultureInfo como parâmetro, provavelmente porque não pode garantir que o servidor SQL manipule culturas da mesma forma que o .NET. Isso não é totalmente verdade, porque ele faz suporte StartsWith(string, StringComparison).

No entanto, ele não parece oferecer suporte a um método que é avaliado LIKEem LINQ to SQL e em uma comparação sem distinção entre maiúsculas e minúsculas no .NET, tornando impossível executar Contains () sem diferenciação de maiúsculas e minúsculas de maneira consistente.


Apenas FYI EF 4.3 não suporta StartsWith. Eu recebo: LINQ to Entities não reconhece o método 'Boolean StartsWith (System.String, System.StringComparison)'
nakhli

StartWith se converte em LIKE 'hello%'?
Bart Calixto

O link clicdata está morto.
Adam Parkin

2
grande esforço para cavar o comportamento SQL e db gerado por cláusula LIKE
Thariq Nugrohotomo

1
Então, quais são as opções ao usar o EF? Em um contexto, preciso fazer uma insensitivepesquisa de caso e, no outro, preciso case sensitive. Eu só tenho que aguentar o desempenho e usar 'toLower ()'?
Zapnologica

12

A resposta aceita aqui não menciona o fato de que, se você tiver uma sequência nula, ToLower () lançará uma exceção. A maneira mais segura seria fazer:

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

Você não pode gen uma exceção em uma consulta traduzido para SQL
Alex Zhukovskiy

@AlexZhukovskiy Como isso é relevante para esse problema? Se fi.DESCRIPTION for nulo ou a descrição for nula, você está recebendo uma exceção de referência nula em C #. Não importa o que a consulta LINQ converte no lado SQL. Aqui está a prova: dotnetfiddle.net/5pZ1dY
Marko

Porque esta consulta falhará na conversão para SQL porque não suporta o operador de coalescência nula. E você provavelmente está consultando o banco de dados em vez de carregar todas as entradas para usar coalescência nula no lado do cliente. Portanto, se você usá-lo - tudo está bem no lado do cliente, mas falha no DB, caso contrário, você está bem com o DB e não se importa com nullref no lado do cliente, porque isso não acontecerá porque o C # não executa essa consulta e não realmente lê objetos nulos.
Alex Zhukovskiy

Essa resposta me ajudou a resolver um problema que eu estava obtendo no LINQ to Entities onde eu estava executando .IndexOf e .Contains em um IEnumerable onde o valor da string proveniente do banco de dados era nulo. Eu não estava recebendo o erro até que o resultado fosse enumerado e recebi uma mensagem de erro "Referência de objeto não definida para uma instância de um objeto". Eu não conseguia descobrir por que estava ocorrendo até ver este post. Obrigado!
randyh22

7

Usando o C # 6.0 (que permite funções corporais de expressão e propagação nula), para LINQ to Objects, isso pode ser feito em uma única linha como esta (também verificando se é nulo):

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

Não está funcionando porque ContainsInsensitive não é um comando loja
Sven

@ Sven - sim, funciona apenas para LINQ to Objects. Eu consertei minha resposta. Obrigado.
Alexei

4

IndexOf funciona melhor neste caso

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

3

Você pode usar string.Compare

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

se você quiser apenas verificar o conteúdo, use "Qualquer"

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

Isso não responde à pergunta. O OP está perguntando sobre 'Contém' dentro de uma string (ou seja, uma string contém outra), não se uma coleção de strings contém uma única string.
andrewf 10/04

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

2
podemos usar métodos de extensão personalizados em consultas linq? você tem certeza ?
Vishal Sharma


0

Honestamente, isso não precisa ser difícil. Pode parecer que no início, mas não é. Aqui está uma consulta linq simples em C # que faz exatamente como solicitado.

No meu exemplo, estou trabalhando com uma lista de pessoas que têm uma propriedade chamada FirstName.

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

Isso pesquisará o banco de dados na pesquisa em minúsculas, mas retornará resultados completos.


-2

Use o método String.Equals

public IQueryable<FACILITY_ITEM> GetFacilityItemRootByDescription(string description)
{
    return this.ObjectContext.FACILITY_ITEM
           .Where(fi => fi.DESCRIPTION
           .Equals(description, StringComparison.OrdinalIgnoreCase));
}
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.