6

I have the following class:

public class testClass
{
    public string name { get; set; }
    public int id { get; set; }
    public int age { get; set; }
}

and the following code:

            var list = new List<testClass>();
            list.Add(new testClass { name = "name", id = 1, age = 30 });
            list.Add(new testClass { name = "name", id = 2, age = 22 });
            list.Add(new testClass { name = "name", id = 3, age = 20 });
            list.Add(new testClass { name = "name", id = 4, age = 30 });
            list.Add(new testClass { name = "name", id = 5, age = 27 });
            list.Add(new testClass { name = "name", id = 6, age = 30 });

            var qble = list.AsQueryable();

            var pred = PredicateBuilder.New<testClass>();
            pred.Or(x => x.name == "name" && x.id == 1);
            pred.Or(x => x.age == 30);
            var predQuery = qble.AsExpandable().Where(pred);

My aim is to create a query that returns all records where:

id = 1 and name = "name"

OR

age = 30

So for the query above, it should return the items at index 0, 1, 5

For the above query it does as I want.

However, I now want to the build the predicate by combining a set of queries, rather than explicitly defining them. So I now have the following 2 queries:

var query1 = list.Where(x => x.name == "name" && x.id == 1);
var query2 = list.Where(x => x.age == 30);

and I want to build the query based on the variables query1 and query2, without explicitly defining the conditions - as these conditions will be dynamically defined and I do not know what they are,and they will be defined in different places.

My guess is I need to do something like this (continuing from above):

var qble = list.AsQueryable();

var query1 = list.Where(x => x.name == "name" && x.id == 1);
var query2 = list.Where(x => x.age == 30);

var pred = PredicateBuilder.New<testClass>();
pred.Or(query1);
pred.Or(query2);
var predQuery = qble.AsExpandable().Where(pred);

but this is not quite correct as the predicate builder will not accept the query as a parameter.

Can this be done?

Alex
  • 3,730
  • 9
  • 43
  • 94
  • Is there a need to separate the queries? – jonathan.ihm Aug 30 '17 at 13:45
  • @jonathan.ihm I am not sure what you mean? – Alex Aug 30 '17 at 13:46
  • 1
    This sounds like an [xy problem](https://meta.stackexchange.com/questions/66377/what-is-the-xy-problem). What is it you are actually trying to solve/build? What is the "big picture"? – Igor Aug 30 '17 at 13:46
  • @Alex I mean Can't you just do x.name == "name" && x.id == 1 || x.age == 30 – jonathan.ihm Aug 30 '17 at 13:47
  • @Igor I am trying to create an dynamic OR clause – Alex Aug 30 '17 at 13:47
  • @jonathan.ihm no because the and clause is being built up in one place and then I need to check against a further condition and combine the results – Alex Aug 30 '17 at 13:47
  • Is someting like this? https://stackoverflow.com/questions/782339/how-to-dynamically-add-or-operator-to-where-clause-in-linq?rq=1 – bruno.almeida Aug 30 '17 at 13:49
  • @Igor it does not have to be predicates. I one place I am building up an AND clause, and then further down the line I need to check if either the AND clause is true, or if a further conditions is true – Alex Aug 30 '17 at 13:49
  • What do you mean by "Dynamic"? Is this a function and consumer of function will provide two filter expressions? – sallushan Aug 30 '17 at 13:56
  • @sallushan By dynamic I mean the where clause is built up using a function depending on what parameters are passed into the query, and then added to the query – Alex Aug 30 '17 at 13:58
  • @Alex Is there any reason you can't use `Union`? – yinnonsanders Aug 30 '17 at 14:24
  • @yinnonsanders the query could be very big and I do not want it to run twice, I want to build it up and then run it once – Alex Aug 30 '17 at 14:25

1 Answers1

4

You could create two Predicate<T> and invoke them in your .Where call at the end.

var qble = list.AsQueryable();

var query1 = new Predicate<testClass>(x => x.name == "name" && x.id == 1);
var query2 = new Predicate<testClass>(x => x.age == 30);

var predQuery = qble.AsExpandable().Where(x => query1(x) || query2(x));

Or you could build another Predicate<T> beforehand and use this

var query = new Predicate<testClass>(x => query1(x) || query2(x));
var predQuery = qble.AsExpandable().Where(query);
Philippe Paré
  • 4,279
  • 5
  • 36
  • 56