2

I use linqToEntities and would like to add OR condition dynamically.

I know that there is a great library PredicateBuilder by brother Albahari and it can solve my task, but I cannot use it.

My conditions looks like this:

IEnumerable<Condition> conditions = new List<Condition>()
{
    new Condition(){IdReference = 1, TableName = "Table1" },
    new Condition(){IdReference = 2, TableName = "Table2" },
    new Condition(){IdReference = 3, TableName = "Table3" }, 
    // and so on
};

What I have is:

var histories = db.History as IQueryable<History>;
foreach (var cond in conditions)
{
     //What code should be here to be translated into:
     /*
     histories = histories
        .Where(h => h.IdReference == 1 && h.TableName =="Table1" 
            || h.IdReference == 2 && h.TableName == "Table2"
            || h.IdReference == 3 && h.TableName == "Table3");
            // and so on
     */
}    

However, I do not know in advance how many conditions would be. How is it possible to add OR conditions dynamically from IEnumerable<Condition>?

StepUp
  • 36,391
  • 15
  • 88
  • 148
  • 1
    If you don't have too many combinations, just use some conditions: `if(thisIsTheCase){ histories = histories.Where(// put your conditions} else if(another Case){ histories = histories.Where(// put your conditions}` add more if else until you have covered all cases. You can also do it by creating dynamic expressions but it will not be easy because you will need to combine the expressions. – CodingYoshi Nov 11 '18 at 14:21
  • 2
    Why can you not use `PredicateBuilder`? – CodingYoshi Nov 11 '18 at 14:48
  • @CodingYoshi as my code will not be passed a code review. – StepUp Nov 11 '18 at 16:23

2 Answers2

2

Not sure what's the problem with using predicate builder - it doesn't have to be LINQ Kit package, the so called predicate builder is usually a single static class with 2 extension methods - like Universal Predicate Builder or my own PredicateUtils from Establish a link between two lists in linq to entities where clause and similar.

Anyway, once you want it, of course it could be built using just plain Expression class static methods.

Add the following in order to eliminate the need of writing Expression. before each call:

using static System.Linq.Expressions.Expression;

and then use something like this:

if (conditions.Any())
{
    var parameter = Parameter(typeof(History));
    var body = conditions
        .Select(condition => Expression.Constant(condition))
        .Select(condition => Expression.AndAlso(
        Expression.Equal(
            Expression.PropertyOrField(parameter, nameof(History.IdReference)),
            Expression.Convert(
                  Expression.PropertyOrField(condition, nameof(Condition.IdReference))
                , Expression.PropertyOrField(parameter, nameof(History.IdReference)).Type)
        ),
        Expression.Equal(
            Expression.PropertyOrField(parameter, nameof(History.TableName)),
            Expression.Convert(
                  Expression.PropertyOrField(condition, nameof(Condition.TableName))
                , Expression.PropertyOrField(parameter, nameof(History.TableName)).Type)
         )
        ))
        .Aggregate(Expression.OrElse);                      
    var predicate = Lambda<Func<History, bool>>(body, parameter);
    histories = histories.Where(predicate);
}
StepUp
  • 36,391
  • 15
  • 88
  • 148
Ivan Stoev
  • 195,425
  • 15
  • 312
  • 343
0

As I understand you mean

var histories = db.History as IQueryable<History>;
foreach (var cond in conditions)
{
     //What code should be here to be translated into:

     histories = histories
        .Where(h => h.IdReference == cond.IdReference && 
      h.TableName ==cond.TableName );

}