Search code examples
c#linqlambdaexpression-trees

LINQ to object and universal PredicateBuilder does not seem to play well together


I have a scenario to use codes below to simplify the explanation here.

I have a model class

class Model
{
    public string CodeLevel1 { get; set; }
    public string CodeLevel2 { get; set; }
    public bool IsVoluntary { get; set; }
}

It is obvious that I will build a list of objects

        var models = new List<Model>
        {
            new Model()
            {
                CodeLevel1 = "32",
                CodeLevel2 = "A1",
                IsVoluntary = false
            },
            new Model()
            {
                CodeLevel1 = "32",
                CodeLevel2 = "A2",
                IsVoluntary = true
            },
            new Model()
            {
                CodeLevel1 = "33",
                CodeLevel2 = "A3",
                IsVoluntary = true
            },
            new Model()
            {
                CodeLevel1 = "34",
                CodeLevel2 = "A4",
                IsVoluntary = false
            },
            new Model()
            {
                CodeLevel1 = "34",
                CodeLevel2 = "A5",
                IsVoluntary = false
            },
            new Model()
            {
                CodeLevel1 = "34",
                CodeLevel2 = "A6",
                IsVoluntary = true
            },
        };

I want to use PredicateBuilder introduced in A universal PredicateBuilder to build dynamic query. Following code is just my first step of attempt.

var configs = new Dictionary<string, List<string>>()
{
    { "32", new List<string>() { "A1", "A2"} },
    { "33", new List<string>() { "A3" } },
};
var predicate = PredicateBuilder.False<Model>();
var allLevel1CodesInConfig = (from c in configs select c.Key).ToList();
predicate.Or(x => !allLevel1CodesInConfig.Contains(x.CodeLevel1) && x.IsVoluntary == false);
var filteredList = models.AsQueryable().Where(predicate).ToList();

I get nothing in the filteredList, but if I rewrite the last line of code I get what I am expecting.

var filteredList = models.AsQueryable().Where(x => !allLevel1CodesInConfig.Contains(x.CodeLevel1) && x.IsVoluntary == false).ToList();

I need some help to understand why the predicate in Where does not work for me?


Solution

  • The problem is in this line:

    predicate.Or(x => !allLevel1CodesInConfig.Contains(x.CodeLevel1) && x.IsVoluntary == false);
    

    Change it to:

    predicate = predicate.Or(x => !allLevel1CodesInConfig.Contains(x.CodeLevel1) && x.IsVoluntary == false);
    

    Each PredicateBuilder method creates a new predicate and does not mutate the original one.