Reputation:
Is there anyway to join LINQ where clauses as OR ?
var ints = new [] { 1, 3, 5, 7 };
var query = from i in ints select i;
query = query.Where (q => q == 3);
query = query..Where (q => q == 7);
What I want is the ability to dynamically add where clauses but make them use OR instead of AND
Upvotes: 17
Views: 7331
Reputation: 1414
You can using Union method:
var ints = new [] { 1, 3, 5, 7 };
var query = ints.Where(q => q == 3);
query = query.Union(ints.Where(q => q == 7));
Upvotes: 1
Reputation: 1
I am trying to do something similar. Here's what I came up with:
//various test cases
bool useTestCase1 = true;
bool useTestCase2 = true;
bool useTestCase3 = false;
query = query.Where(q =>
(q == 3 && useTestCase1 ) ||
(q == 7 && useTestCase2 ) ||
(q == 10 && useTestCase3 )
);
Upvotes: -3
Reputation: 43513
Using ExpressionVisitor
to help to build the expression base on two expressions with OR/AND relationship. This answer is from Jeffery Zhao's blog.
internal class ParameterReplacer : ExpressionVisitor
{
public ParameterReplacer(ParameterExpression paramExpr)
{
this.ParameterExpression = paramExpr;
}
public ParameterExpression ParameterExpression { get; private set; }
public Expression Replace(Expression expr)
{
return this.Visit(expr);
}
protected override Expression VisitParameter(ParameterExpression p)
{
return this.ParameterExpression;
}
}
public static Expression<Func<T, bool>> And<T>(this Expression<Func<T, bool>> one, Expression<Func<T, bool>> another)
{
var candidateExpr = Expression.Parameter(typeof(T), "candidate");
var parameterReplacer = new ParameterReplacer(candidateExpr);
var left = parameterReplacer.Replace(one.Body);
var right = parameterReplacer.Replace(another.Body);
var body = Expression.And(left, right);
return Expression.Lambda<Func<T, bool>>(body, candidateExpr);
}
public static Expression<Func<T, bool>> Or<T>(this Expression<Func<T, bool>> one, Expression<Func<T, bool>> another)
{
var candidateExpr = Expression.Parameter(typeof(T), "candidate");
var parameterReplacer = new ParameterReplacer(candidateExpr);
var left = parameterReplacer.Replace(one.Body);
var right = parameterReplacer.Replace(another.Body);
var body = Expression.Or(left, right);
return Expression.Lambda<Func<T, bool>>(body, candidateExpr);
}
Upvotes: 3
Reputation: 6476
If you want to stay with your strong-typing Linq queries you should look into LinqKit and predicate building. I have used this for something similar and found it to work well with And / Or stacking of filters.
Check out the C#4.0/3.0 in a Nutshell excerpt for more in depth info. Here is a snip from my code:
//Setup the initial predicate obj then stack on others:
basePredicate = basePredicate.And(p => false);
var predicate1 = PredicateBuilder.True<Person>();
foreach (SearchParms parm in parms)
{
switch (parm.field)
{
case "firstname":
predicate1 = predicate1.And(p => p.FirstName.Trim().ToLower().Contains(sValue));
break;
//etc...
}
}
//Run a switch based on your and/or parm value to determine stacking:
if (Parm.isAnd) {
basePredicate = basePredicate.And(predicate1);
} else {
basePredicate = basePredicate.Or(predicate1);
}
Upvotes: 16
Reputation: 38860
How about something like this?
var query = from i in ints where CheckConditions(i) select i;
public bool CheckConditions(int i)
{
var conditions = WhereConditions; //an IEnumerable<Func<int, bool>> of dynamically added conditions
foreach (var condition in conditions)
{
if (condition(i)) return true;
}
return false;
}
You can probably expand this to be a bit cleverer but that's sort of how I'd do it.
EDIT: Sorry the first example was an AND, have changed it now to be an OR. So the first time it encounters a passing condition it returns true.
Upvotes: 3
Reputation: 14662
try this
var ints = new [] { 1, 3, 5, 7 };
var query = ints.select(X=>X).where(X=>X==3||X==7);
Upvotes: -3
Reputation: 6103
Are you talking about specifying more than one condition in the lambda?
query = query.Where(q => q == 3 ||
q == 7);
Upvotes: -2