Dynamic Linq query not working as expected - what am I doing wrong?

c# dynamic-linq linq

Question

I'm trying to build a basic dynamic Linq query using LinqPad. My method asks users to select 1 - 3 options, and then dynamically builds the query based on their input.

public void FilteredPropertySearch()
{
    bool addAnotherOption = true;
    int option;
    Dictionary<int, bool> parameters = new Dictionary<int, bool>();
    var predicate = PredicateBuilder.False<ResidentialProperty>();

    Console.WriteLine("Follow instructions to filter property search results");

do
{
    // get user input

    option = int.Parse(Console.ReadLine());

    switch(option)
    {
        case 1:
            parameters.Add(1, true);
            break;

    // more cases - when case 0 addAnotherOption = false, loop ends

        default:
            Console.WriteLine("That was not a valid option");
            break;
    }

}while(addAnotherOption == true);

    foreach(KeyValuePair<int, bool> p in parameters)
{   
    if(p.Key == 1 && p.Value == true)
        predicate = predicate.Or (c => c.HasBackGarden);
    if(p.Key == 2 && p.Value == true)
        predicate = predicate.Or (c => c.HasFrontGarden);
    if(p.Key == 3 && p.Value == true)
        predicate = predicate.Or (c => c.HasSecureParking);
}

ResidentialProperties.Where (predicate).Dump();

}

The foreach loop should build the query based on the user's input, but when, for example, I make the first value in the dictionary true and select no others, it doesn't return any results. It definitely should as I know there are some values in my database table that satisfy Key(1) being true.

Should I be doing something else with query after the if's in the foreach?

EDIT

I've used the predicate builder instead and it seems to be (kind of) working when I use predicate.Or (as per edited code), but it only returns the first option that I select, it's not building an expression tree. I thought that changing predicate.Or to predicate.And would have added each selected user input to a filter expression.

If all three options were selected by the user, I want only rows to be returned where columns HasBackGarden, HasFrontGarden and HasSecureParking are true. How do I accomplish this?

1
1
2/24/2013 5:07:32 PM

Accepted Answer

If you want to restrict your result set to those records that satisfy all of the conditions, then you are correct that you should use .And instead of .Or, but in order to do that, you need to start with PredicateBuilder.True<ResidentialProperty>() instead of False.

This is because before any filters are added, the correct result set contains all records, and each subsequent filter restricts the result set. If you start with False, none of the records can ever possibly satisfy the predicate.

3
4/9/2013 11:21:25 PM

Popular Answer

From your code it looks like you are operating on the var "query" which is an empty enumerable. Remember, what you have called query is the data set, the Where statement is the query on that data set. So the first query is on an empty data set and it looks like the additional queries from the foreach will just refine that empty set.

Also, you can just do .Where(q => q.HasWhatever) since those are bools.



Related Questions





Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow