Utilizzando contiene () in LINQ to SQL
-
24-09-2019 - |
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?
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 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 query[0]
, query[1]
, e
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 AND
s 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;
}