Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

filter IQueryable in a loop with multiple Where statements

Tags:

c#

linq

i have this code

private static IQueryable<Persoon> Filter(IQueryable<Persoon> qF, IDictionary<string, string> filter)
{
    IQueryable<Persoon> temp;
    temp = qF;
    foreach (var key in filter)
    {
        if (key.Key == "naam")
        {
            temp = temp.Where(f => f.Naam == key.Value);
        }
        else if (key.Key == "leeftijd")
        {
            temp = temp.Where(af => af.Leeftijd != null && af.Leeftijd.AantalJaarOud.ToString() == key.Value);
        }
    }
    return temp;

}

what it does (it's a simplified version which is made to test the behaviour) is that you give this function a IQueryable of Persoon (from the database) and a list of filters.

So you give the filter naam,john and leefttijd,30 you get all Persoon objecten named John and Age 30.

When i enter the loop first, right after i do the first where (the leeftijd where) at the } after it, i see that tmp has 3 objects. Then the code goes for the second time in the loop, enters the first If (where filter eq naam) and right there, when i look at tmp, it only has 0 objects.

what the first view of it not working was, was the fact that the function returns no results (should be 2: 3 30's and 2 Johns of those). So i concluded that the multiple .Where was the problem.

But now i see that the temp is empty even BEFORE i do the second where.

What am i doing wrong?

like image 785
Michel Avatar asked Feb 25 '23 02:02

Michel


1 Answers

LINQ's lambda expressions use late parameter binding so when the xpression is finally processed the variable "key" no longer points at the right values.

Try changing your code to store key in a local variable and use it instead:

private static IQueryable<Persoon> Filter(IQueryable<Persoon> qF, IDictionary<string, string> filter)
{
    IQueryable<Persoon> temp;
    temp = qF;
    foreach (var key in filter)
    {
        var currentKeyValue = key.Value;
        if (key.Key == "naam")
        {
            temp = temp.Where(f => f.Naam == currentKeyValue);
        }
        else if (key.Key == "leeftijd")
        {
            temp = temp.Where(af => af.Leeftijd != null && af.Leeftijd.AantalJaarOud == Int32.Parse(currentKeyValue));
        }
    }
    return temp;

}

Another thing I think you should change is the casting of the age field to string rather than the opposite direction. therefore the database is comparing numbers rather than strings.

like image 53
Variant Avatar answered May 15 '23 15:05

Variant