Domanda

Sto cercando di implementare una ricerca per parole chiave molto di base in un'applicazione utilizzando LINQ to SQL. I miei termini di ricerca sono in un array di stringhe, ogni elemento dell'array di essere una sola parola, e mi piacerebbe trovare le righe che contengono i termini di ricerca. Non mi dispiace se contengono più che i termini di ricerca (molto probabilmente, lo faranno), ma tutti i termini di ricerca non devono essere presenti.

Idealmente, vorrei qualcosa di simile al frammento di sotto, ma so che questo non funzionerà. Inoltre, ho guardato questa domanda qui , ma l'autore di tale questione sembra contento di fare le cose il contrario (query.Contains(part.partName)), che non funziona per me.

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

Come posso riscrivere la query in modo che possa fare quello che mi serve?

È stato utile?

Soluzione

Guardando le altre rattrista tentativi me: (

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

Ipotesi:

  • sguardi nomeparte come: "ABC 123 XYZ"

  • query è { "ABC", "123", "XY"}

Altri suggerimenti

Una soluzione più semplice e più corretta (allora di 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;
}

Ciò funzionerà finché partName è una stringa (o un equivalente SQL di una stringa).

La cosa importante da notare è partName.Contains(qs) è diverso da query.Contains(partName) .
Con partName.Contains(qs), partName viene cercato per qualsiasi occorrenza di qs. Lo SQL risultante sarebbe equivalente (dove è il valore di qs):

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

Anche di nota sono StartsWith e EndsWith che sono simili a Contains ma look per la stringa nella posizione specifica.

query.Contains(partName) è lo stesso di un in comando SQL. Lo SQL risultante sarebbe equivalente a (dove è il valore di query[0], è il valore di query[1], e è l'ultimo valore nella matrice query):

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

Aggiornamento:
E 'anche importante notare che la risposta di leppie non sfugge i caratteri jolly prima di aggiungerli al come dichiarazione . Questo non è un problema con la soluzione Contains dal LINQ sfuggirà la query prima di inviarlo. Una versione sfuggito della soluzione SqlMethods.Like potrebbe essere:

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

Non c'è bisogno di preoccuparsi 'dal LINQ sfuggirà che per voi.

Si potrebbe provare:

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

Tuttavia, non sono sicuro se LINQ to SQL sarà in grado di trasformarla in T-SQL. Un'altra opzione potrebbe essere:

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

Non è così bella, ma dovrebbe funzionare. Otterrete una query con un sacco di ANDs nella clausola WHERE.

Si può scrivere come questo

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

Usando il pacchetto NinjaNye.SearchExtension NuGet consente di eseguire questa ricerca con facilità:

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

Si potrebbe anche cercare di più le proprietà di stringa

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

o eseguire una RankedSearch che restituisce IQueryable<IRanked<T>> che comprende semplicemente una proprietà che mostra quante volte sono apparsi i termini di ricerca:

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

V'è una più ampia guida sui progetti pagina GitHub: https://github.com/ninjanye/SearchExtensions

Spero che questo aiuti futuri visitatori

Sento che questo è un po 'semplice e di lavoro per me:

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

Si prega di provare questo:

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;
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top