I\'m trying to implement a very basic keyword search in an application using linq-to-sql. My search terms are in an array of strings, each array item being one word, and I
You can write it as this
var result = db.Parts.Where(p => query.All(q => p.partName.Contains(q)));
Looking at the other attempts saddens 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;
}
Assumptions:
partName looks like: "ABC 123 XYZ"
query is { "ABC", "123", "XY" }
I feel this is somewhat simple and working for me:
string[] product = products.Split(',');
using (var context = new ProjectTrackerEntities())
{ var result = from part in context.DBAudits where product.Contains(part.TableName) select part; }
A simpler and more correct solution (then leppie's):
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;
}
This will work as long as partName
is a string (or an SQL equivalent of a string).
The important thing to note is partName.Contains(qs) is different than query.Contains(partName).
With partName.Contains(qs)
, partName
is searched for any occurrence of qs
. The resulting SQL would be equivalent (where <qs> is the value of qs
):
select * from Parts where partName like '%<qs>%';
Also of note are StartsWith and EndsWith which are similar to Contains but look for the string in the specific location.
query.Contains(partName)
is the same as a SQL in command. The resulting SQL would be equivalent to (where <query0> is the value of query[0]
, <query1> is the value of query[1]
, and <queryN> is the last value in the query array):
select * from Parts where partName in ( <query0>, <query1>, ..., <queryN> );
Update:
It is also important to note that leppie's answer does not escape the wildcard characters before adding them to the like statement. This is not an issue with the Contains solution since Linq will escape the query before sending it. An escaped version of the SqlMethods.Like
solution would be:
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;
}
You don't have to worry about ' since Linq will escape that for you.
You could try:
public IQueryable<Part> SearchForParts(string[] query)
{
return from part in db.Parts
where query.All(term => part.partName.Contains(term))
select part;
}
However, I'm not sure if LINQ to SQL will be able to transform it into T-SQL. Another option would be:
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;
}
It's not as pretty, but it should work. You'll get a query with a lot of AND
s in the where clause.
please try this:
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;
}