tags:

views:

630

answers:

3

Starting with the following LINQ query:

from a in things  
where a.Id == b.Id &&  
a.Name == b.Name &&  
a.Value1 == b.Value1 &&  
a.Value2 == b.Value2 &&  
a.Value3 == b.Value3  
select a;

How can I remove (at runtime) one or more of the conditions in the where clause in order to obtain queries similar to the following ones:

from a in things  
where a.Id == b.Id &&  
a.Name == b.Name &&  
a.Value2 == b.Value2 &&  
a.Value3 == b.Value3  
select a;

Or

from a in things  
where 
a.Name == b.Name &&  
a.Value3 == b.Value3  
select a;
+5  A: 

Rather than try to change existing where clauses, I'd refactor it to this:

from a in things  
where a.Id == b.Id 
where a.Name == b.Name 
where a.Value1 == b.Value1
where a.Value2 == b.Value2
where a.Value3 == b.Value3  
select a;

That then becomes:

things.Where(a => a.Id == b.Id)
      .Where(a => a.Name == b.Name)
      .Where(a => a.Value1 == b.Value1)
      .Where(a => a.Value2 == b.Value2)
      .Where(a => a.Value1 == b.Value3);

Now it should be reasonably clear how to proceed - conditionalise the calls to Where:

IQueryable<Whatever> query = things;
if (useId) {
    query = query.Where(a => a.Id == b.Id);
}
query = query.Where(a => a.Name == b.Name);
if (checkValue1) {
    query = query.Where(a => a.Value1 == b.Value1);
}
// etc
Jon Skeet
Do the chained calls generate AND's in the SQL? If so, how would you achieve a similar thing with OR's? How would you conditionalise WHERE x=y OR p=r OR ...
Greg B
+1  A: 

This may be another approach to it too;

bool executeValue1Condition = true;
bool executeValue2Condition = true;
bool executeValue3Condition = true;

var q = from a in things  
where a.Id == b.Id &&  
a.Name == b.Name &&  
(a.Value1 == b.Value1 || executeValue1Condition) &&  
(a.Value2 == b.Value2 || executeValue2Condition) &&  
(a.Value3 == b.Value3 || executeValue3Condition) 
select a;

executeValue1Condition = false;
q = q.Select(i => i);

And also by using this approach, you can change your condition after your query is executed but of course by a new execution.

yapiskan
That might not work so well depending on the provider... it would be better to simply not include them (as per Jon's)
Marc Gravell
Hmm, can you please say in which case? What provider do you mean?
yapiskan
A: 

Try to separate things. First isolate the where condition from the rest of your query then process it and use standard query methods instead of the built in syntactic sugar. Eg.:

     IQueryable<MyClass> things = null;
     MyClass b = new MyClass();

     Expression<Func<MyClass, bool>> whereExp = a => a.Id == b.Id && a.Name == b.Name;
     // process where expression here. it's just an expression tree. traverse it and
     // remove nodes as desired.
     var result = things.Where(whereExp).Select(a => a);

Another easier mode to achieve this would be not to start with a full expression and removing things but instead compose one from parts. Eg.:

IQueryable<MyClass> things = null;
MyClass b = new MyClass();

Expression<Func<MyClass, bool>> whereExp;
Expression<Func<MyClass, bool>> exp1 = a => a.Id == b.Id;
Expression<Func<MyClass, bool>> exp2 = a => a.Name == b.Name;
whereExp = Expression.Lambda<Func<MyClass, bool>>(Expression.And(exp1, exp2), Expression.Parameter(typeof(MyClass), "a"));

var result = things.Where(whereExp).Select(a => a);
AZ