Pergunta

Estou tentando implementar uma pesquisa de palavras-chave muito básica em um aplicativo usando o LINQ para SQL. Meus termos de pesquisa estão em uma matriz de strings, sendo cada item de matriz uma palavra, e eu gostaria de encontrar as linhas que contêm os termos de pesquisa. Não me importo se eles contiverem mais do que apenas os termos de pesquisa (provavelmente, eles o farão), mas todos os termos de pesquisa precisam estar presentes.

Idealmente, eu gostaria de algo semelhante ao trecho abaixo, mas sei que isso não funcionará. Além disso, eu olhei para esta questão aqui, mas o autor dessa pergunta parece contente em fazer as coisas de outra maneira ( query.Contains(part.partName) ), o que não funciona para mim.

public IQueryable<Part> SearchForParts(string[] query)
{
    return from part in db.Parts
           where part.partName.Contains(query)
           select part;
}

Como posso reescrever essa consulta para que ela faça o que eu preciso?

Foi útil?

Solução

Olhando para as outras tentativas me entristece :(

public IQueryable<Part> SearchForParts(string[] query)
{
  var q = db.Parts.AsQueryable(); 

  foreach (var qs in query)
  { 
    var likestr = string.Format("%{0}%", qs);
    q = q.Where(x => SqlMethods.Like(x.partName, likestr));
  }

  return q;
}

Suposições:

  • PartName parece: "ABC 123 XYZ"

  • Query é {"abc", "123", "xy"}

Outras dicas

Uma solução mais simples e mais correta (então de Leppie):

public IQueryable<Part> SearchForParts(string[] query)
{
    var q = db.Parts.AsQueryable(); 

    foreach (string qs in query)
    {
        q = q.Where(x => x.partName.Contains(qs));
    }

    return q;
}

Isso funcionará enquanto partName é uma string (ou um equivalente SQL de uma string).

O importante a ser observado é partName.Contains(qs) é diferente de query.Contains(partName).
Com partName.Contains(qs), partName é pesquisado por qualquer ocorrência de qs. O SQL resultante seria equivalente (ondeu003Cqs> é o valor de qs):

select * from Parts where partName like '%<qs>%';

Também de nota são StartsWith e EndsWith que são semelhantes a Contains Mas procure a string no local específico.

query.Contains(partName) é o mesmo que um SQL in comando. O SQL resultante seria equivalente a (ondeu003Cquery0> é o valor de query[0], Assim,u003Cquery1> é o valor de query[1], eu003CqueryN> é o último valor na matriz de consultas):

select * from Parts where partName in ( <query0>, <query1>, ..., <queryN> );

Atualizar:
Também é importante observar que a resposta de Leppie não escapa dos caracteres curinga antes de adicioná -los ao Curti declaração. Este não é um problema com o Contains Solução Como o LINQ escapará da consulta antes de enviá -la. Uma versão escapada do SqlMethods.Like Solução seria:

public IQueryable<Part> SearchForParts(string[] query)
{
    var q = db.Parts.AsQueryable(); 

    foreach (var qs in query)
    {
        string escaped_bs = qs.Replace("/", "//"),
            escaped_us = escaped_bs.Replace("_", "/_"),
            escaped_p = escaped_us.Replace("%", "/%"),
            escaped_br = escaped_p.Replace("[", "/["),
            likestr = string.Format("%{0}%", escaped_br);

        q = q.Where(x => SqlMethods.Like(x.partName, likestr, '/'));
    }

    return q;
}

Você não precisa se preocupar com o que o Linq escapará disso para você.

Você poderia tentar:

public IQueryable<Part> SearchForParts(string[] query)
{
    return from part in db.Parts
           where query.All(term => part.partName.Contains(term))
           select part;
}

No entanto, não tenho certeza se o LINQ para SQL poderá transformá-lo em T-SQL. Outra opção seria:

public IQueryable<Part> SearchForParts(string[] query)
{
    var result = from part in db.Parts
                 select part;

    foreach(var term in query)
    {
        result = from part in result
                 where part.partName.Contains(term)
                 select part;
    }

    return result;
}

Não é tão bonito, mas deve funcionar. Você terá uma consulta com muito ANDestá na cláusula onde.

Você pode escrever como este

var result = db.Parts.Where(p => query.All(q => p.partName.Contains(q)));

Usando o Ninjanye.searchExtension O pacote Nuget permite que você execute esta pesquisa com facilidade:

string[] terms = new[]{"search", "term", "collection"};
var result = db.Parts.Search(terms, p => p.PartName);

Você também pode pesquisar várias propriedades da string

var result = db.Parts.Search(terms, p => p.PartName, p.PartDescription);

Ou execute um RankedSearch que retorna IQueryable<IRanked<T>> que simplesmente inclui uma propriedade que mostra quantas vezes os termos de pesquisa apareceram:

//Perform search and rank results by the most hits
var result = db.Parts.RankedSearch(terms, p => p.PartName, p.PartDescription)
                     .OrderByDescending(r = r.Hits);

Há um guia mais extenso na página do Github Projects: https://github.com/ninjanye/searchExtensions

Espero que isso ajude futuros visitantes

Eu sinto que isso é um pouco simples e trabalhando para mim:

string[] product = products.Split(','); 
using (var context = new ProjectTrackerEntities()) 
{ var result = from part in context.DBAudits where product.Contains(part.TableName) select part; }

Por favor, tente isto:

public IQueryable<Part> SearchForParts(string[] query)
{
    return from part in db.Parts
           where Search(part.Name,query)
           select part;
}

public bool Search(string partName,string[] query)
{
    for (int i = 0; i < query.Length; i++)
    {
        if(partName.Contains(query[i]))
           return true;
    }

    return false;
}
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top