Search code examples
c#linqfor-loopwhere-clausepredicatebuilder

PredicateBuilder Not Working in Loop, But Working Manually


I am trying to use LinqKit's PredicateBuilder to create some nested logic to compare against SQL, and this works fine when I manually specify the conditions, but when I place the code in a loop I get an ArgumentOutOfRangeException later on when I try to query based on the predicate I built. Here is my code:

var outerPredicate = PredicateBuilder.New<DataRow>();
var innerPredicate = PredicateBuilder.New<DataRow>();
for (int i = 0; i < 4; i++)
{
    innerPredicate = PredicateBuilder.New<DataRow>();
    for (int j = 0; j < 1; j++)
    {
        innerPredicate = innerPredicate.Or(y => y.Field<string>(sqlNames[i]) == filters[i][j]);
    }
    outerPredicate = outerPredicate.And(innerPredicate);
}

This code always produces the same ArgumentOutOfRangeException, even if I set each loop to run only once, but this code runs perfectly:

var outerPredicate = PredicateBuilder.New<DataRow>();
var innerPredicate = PredicateBuilder.New<DataRow>();
innerPredicate = innerPredicate.Or(y => y.Field<string>(sqlNames[3]) == filters[3][0]);
innerPredicate = outerPredicate.And(innerPredicate);
innerPredicate = PredicateBuilder.New<DataRow>();
innerPredicate = innerPredicate.Or(y => y.Field<string>(sqlNames[2]) == filters[2][0]);
outerPredicate = outerPredicate.And(innerPredicate);
innerPredicate = PredicateBuilder.New<DataRow>();
innerPredicate = innerPredicate.Or(y => y.Field<string>(sqlNames[1]) == filters[1][0]);
outerPredicate = outerPredicate.And(innerPredicate);
innerPredicate = PredicateBuilder.New<DataRow>();
innerPredicate = innerPredicate.Or(y => y.Field<string>(sqlNames[0]) == filters[0][0]);
outerPredicate = outerPredicate.And(innerPredicate);

As far as I can tell, these two pieces of code are functionally identical. I would greatly appreciate anyone who can solve this mystery for me.


Solution

  • This should do it:

       var outerPredicate = PredicateBuilder.New<DataRow>();
        var innerPredicate = PredicateBuilder.New<DataRow>();
        for (int i = 0; i < 4; i++)
        {
            innerPredicate = PredicateBuilder.New<DataRow>();
            for (int j = 0; j < 1; j++)
            {
                var ii=i;var jj=j;
                innerPredicate = innerPredicate.Or(y => y.Field<string>(sqlNames[ii]) == filters[ii][jj]);
            }
            outerPredicate = outerPredicate.And(innerPredicate);
        }
    

    see: Captured variable in a loop in C#