3

I'm writing a query where, based on what input the user has provided, I need to add "disjunctive" conditions (that is to say "or" conditions). To do this with "conjunctive" conditions ("and" conditions"), this is fairly straight forward...

var employees = repository.GetAll<Employee>(); // returns IQueryable
if (!string.IsNullOrEmpty(firstName))
    employees = employees.Where(e => e.FirstName.Contains(firstName));
if (!string.IsNullOrEmpty(lastName))
    employees = employees.Where(e => e.LastName.Contains(lastName));
if (!string.IsNullOrEmpty(email))
    employees = employees.Where(e => e.Email.Contains(email));

The resulting query will have 0 to 3 AND conditions depending on whether firstName, lastName, or email are populated. But is there a way to do this using OR conditions? For example, is there something like the following...

// Notice these use of OrWhere which does not exist...
var employees = repository.GetAll<Employee>(); // returns IQueryable
if (!string.IsNullOrEmpty(firstName))
    employees = employees.OrWhere(e => e.FirstName.Contains(firstName));
if (!string.IsNullOrEmpty(lastName))
    employees = employees.Orwhere(e => e.LastName.Contains(lastName));
if (!string.IsNullOrEmpty(email))
    employees = employees.OrWhere(e => e.Email.Contains(email));

I know that I can make a very large where condition...

var employees = repository.GetAll<Employee>().Where(e =>
    (!string.IsNullOrEmpty(firstName) && e.FirstName.Contains(firstName)) ||
    (!string.IsNullOrEmpty(lastName) && e.LastName.Contains(lastName)) ||
    (!string.IsNullOrEmpty(email) && e.Email.Contains(email))
);

...but the query produced is not efficient and the code does not seem as elegant to me. I'm hoping there's a better way to do this that looks more like the 2nd example.

Aron Boyette
  • 887
  • 9
  • 12
  • 1
    Take some predicate builder (for instance [this one](https://petemontgomery.wordpress.com/2011/02/10/a-universal-predicatebuilder/)) and build `Or` predicate. Or just use the "large where condition" approach - EF Core will eliminate the constant predicate conditions and the resulting queries will be the same as if you were using conditional builder. – Ivan Stoev Apr 06 '20 at 14:32
  • I disagree with the "elegant" part, your code should be clear and as long this is an IQueryable it will be efficient. (Also you should close curly braces) – Sxntk Apr 06 '20 at 14:37
  • @IvanStoev I think the predicate builder is what I need so long as EF Core's linq provider can handle it. I'll test it out and see. – Aron Boyette Apr 06 '20 at 15:20
  • @Sxntk I agree that the single compound or-statement I posted is not hard to read. But the case on which I'm actually working involves much more logic. The or condition would be about 20 lines long, would be very hard to maintain, and would not be readable. I posted this question to find a way of chaining the or-conditions because the logic involved in whether to include the individual or-conditions is much more complicated. As for closing curly braces, I like to live dangerously. – Aron Boyette Apr 06 '20 at 15:26

1 Answers1

0

Here is one way using OR conditions between the null check and the property filter, if that's what you're after...

var employees = repository.GetAll<Employee>(); // returns IQueryable

employees = employees.Where(e => 
    (firstName == null || e.FirstName.Contains(firstName)) && 
    (lastName == null || e.LastName.Contains(lastName)) &&
    (email == null || e.Email.Contains(email)));
Rufus L
  • 36,127
  • 5
  • 30
  • 43