Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PredicateBuilder returning zero records

I'm using PredicateBuilder to create a dynamic Where clause to query data from a DataTable. I have a Dictionary that contains my column names and values I need to search for. I'm simply iterating over the dictionary, if the key matches a column name, then add that key and value to the predicate. Everything seems to work fine until the actual query is run against the datatable, I get zero records back:( But if I replace the dynamic predicate with something like p => p["Year"] == "2010", I get records back. Here's the code:

var objectList = table.AsEnumerable();
Func<DataRow, bool> predicate = GetPredicate(parms, table.Columns);

var list1 = objectList.Where(predicate).ToList();

private static Func<DataRow, bool> GetPredicate(Dictionary <string, string> parms, DataColumnCollection dataColumnCollection)
    {
        var predicate = PredicateBuilder.False<DataRow>();
        foreach (var parm in parms)
        {
            if (dataColumnCollection.Contains(parm.Key))
            {
                var copy = parm;
                predicate = predicate.And(p => p[copy.Key] == copy.Value);
            }
        }
        return predicate.Compile();
    }

Any help would be greatly appreciated:)

like image 748
Pat Lindley Avatar asked Feb 17 '23 21:02

Pat Lindley


1 Answers

You're starting with false and then adding and clauses.

false && ... always returns false, so your Where clause will never match anything.

Try starting with:

var predicate = PredicateBuilder.True<DataRow>();

ALSO:

You are closing over a loop variable, which means all your predicates will use the last parm in parms.

You can fix this by creating a local copy in your loop:

foreach( var parm in parms )
{
  if (dataColumnCollection.Contains(parm.Key))
  {
    var copy = parm;
    predicate = predicate.And( p => p[ copy.Key ] == copy.Value );
  }

UPDATE:

DataRow[ key ] is of type object, so in p[ copy.Key ] == copy.Value, the equality operator is object reference equality, not string equality.

You can fix this by specifying String.Equals:

predicate = predicate.And( p => String.Equals( p[ copy.Key ], copy.Value ) );

Interestingly, this example shows that you can have multiple instances of string with the same contents.

like image 131
Nick Butler Avatar answered Mar 05 '23 02:03

Nick Butler