Question

Je suis en train de mettre en œuvre une recherche par mot clé très basique dans une application utilisant LINQ to SQL. Mes termes de recherche sont dans un tableau de chaînes, chaque élément de réseau étant un mot, et je voudrais trouver les lignes qui contiennent les termes de recherche. Je ne me dérange pas si elles contiennent plus que les termes de recherche (plus probablement, ils), mais tous les termes de recherche ne doivent être présents.

Idéalement, je voudrais quelque chose de similaire à l'extrait ci-dessous, mais je sais que cela ne fonctionnera pas. De plus, je l'ai regardé cette question ici , mais l'auteur de cette question semble se contenter de faire les choses dans l'autre sens (query.Contains(part.partName)), qui ne fonctionne pas pour moi.

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

Comment puis-je réécrire cette requête afin qu'il fera ce que je dois?

Était-ce utile?

La solution

En regardant les autres tentatives me attriste: (

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;
}

Hypothèses:

  • partName ressemble à: "ABC 123 XYZ"

  • requête est { "ABC", "123", "XY"}

Autres conseils

Une solution plus simple et plus correcte (alors leppie de):

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;
}

Cela fonctionne aussi longtemps que partName est une chaîne (ou un équivalent SQL d'une chaîne).

La chose importante à noter est partName.Contains(qs) est différent de query.Contains(partName) .
Avec partName.Contains(qs), partName est recherché toute occurrence de qs. Le SQL résultant serait équivalent (où est la valeur de qs):

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

A noter également StartsWith et EndsWith qui sont semblables à Contains mais regardez la chaîne dans l'emplacement spécifique.

query.Contains(partName) est identique à une commande SQL in . Le SQL résultant serait équivalent à (où est la valeur de query[0], est la valeur de query[1] et est la dernière valeur de la matrice de requête):

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

Mise à jour: Il est également important de noter que la réponse de leppie n'échappe pas les caractères génériques avant de les ajouter à la balise comme déclaration . Ce n'est pas un problème avec la solution Contains depuis Linq va échapper à la requête avant de l'envoyer. Une version échappée de la solution SqlMethods.Like serait:

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;
}

Vous n'avez pas à vous soucier »depuis Linq échappera pour vous.

Vous pouvez essayer:

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

Cependant, je ne suis pas sûr que LINQ to SQL sera en mesure de le transformer en T-SQL. Une autre option serait:

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;
}

Il est pas aussi joli, mais il devrait fonctionner. Vous obtiendrez une requête avec beaucoup de ANDs dans la clause where.

Vous pouvez l'écrire comme cela

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

Utilisation du package NinjaNye.SearchExtension NuGet vous permet d'effectuer cette recherche avec facilité:

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

Vous pouvez également rechercher plusieurs propriétés de chaîne

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

Ou effectuer une RankedSearch qui retourne IQueryable<IRanked<T>> qui comprend simplement une propriété qui montre combien de fois les termes de recherche apparaissent:

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

Il y a un guide plus vaste sur les projets Page GitHub: https://github.com/ninjanye/SearchExtensions

Hope this helps futurs visiteurs

Je pense que c'est un peu simple et de travail pour moi:

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

S'il vous plaît essayez ceci:

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;
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top