I'm trying to iterate for over an string array and dynamically create a IQueryable
query. Its pretty straightforward but here's where I'm stuck
var query = context.QuestionsMetaDatas.AsQueryable();
var keywords=new List<string>(){ "Test1","Test2" };
foreach(var key in keywords)
{
query=query.Where(a=>a.Text.Contains(key));
}
Now the problem is that when the query gets generated its compiles to
select * from QuestionsMetaDatas where Text Like "Test1" AND Text Like "Test2"
Instead of AND
I wanted the query to generate OR
...Now how can I achieve this?
I have used predicate builder like Raphael suggested, it's just one file to include in your project, then your example becomes:
var keywords=new List<string>(){ "Test1","Test2" };
var predicate = PredicateBuilder.False<QuestionsMetaDatas>();
foreach (var key in keywords)
{
predicate = predicate.Or (a => a.Text.Contains (key));
}
var query = context.QuestionsMetaDatas.AsQueryable().Where(predicate);
Generating the OR query your are looking for.
Have you tried contains the other way?
var keywords=new List<int>(){ "Test1","Test2" };
query=query.Where(a=>keywords.Contains(a));
this is like an IN
clause
you could look at predicate builder, or build your own expression (here a possble solution with a static extension method on IQueryable<QuestionsMetadatas>
)
public static IQueryable<QuestionsMetaDatas> FilterText(this IQueryable<QuestionsMetaDatas> queryable, IEnumerable<string> keywords)
{
var entityType = typeof(QuestionsMetaDatas);
var parameter = Expression.Parameter(entityType, "a");
var containsMethod = typeof(string).GetMethod("Contains"
, new[] { typeof(string) });
var propertyExpression = Expression.Property(parameter, "Text");
Expression body = Expression.Constant(false);
foreach (var keyword in keywords)
{
var innerExpression = Expression.Call(propertyExpression, containsMethod, Expression.Constant(keyword));
body = Expression.OrElse(body, innerExpression);
}
var lambda = Expression.Lambda<Func<QuestionsMetaDatas, bool>>(body, new[] { parameter });
return queryable.Where(lambda);
}
where lambda
will look like that :
a => ((False OrElse a.Text.Contains("firstKeyWord")) OrElse a.Text.Contains("secondKeyWord"))
and usage is
var query = context.QuestionsMetaDatas.AsQueryable();
var keywords=new List<string>(){ "Test1","Test2" };
query = query.FilterText(keywords);
or shorter
var query = context.QuestionsMetaDatas.AsQueryable().FilterText(new[]{"Test1", "Test2"});