9

The following code:

var dynamicQuery = from a in _context.Users select a;
string[] args = new string[] { "aa", "bb", "cc" };
foreach (string word in args)
    dynamicQuery = dynamicQuery.Where(x => x.Name.Contains(word));
return dynamicQuery.ToList();

Will allow me to create a Linq query with a dynamic list of AND expressions.

But suppose I wanted to do the same, only with a dynamic list of OR expressions?

Anthony Pegram
  • 123,721
  • 27
  • 225
  • 246
sternr
  • 6,216
  • 9
  • 39
  • 63

1 Answers1

11

You don't need to loop at all:

return _context.Users.Where(x => args.Any(word => x.Name.Contains(word)));

EDIT: More generally, you can use:

Func<User, bool> predicate = user => false;
foreach (var item in items)
{
    var predicateCopy = predicate;
    predicate = user => predicateCopy(user) || someOtherCondition;
}
return query.Where(predicate);

This will end up with quite deep stacks (with one delegate calling another calling another etc). Where the specific situation allows you to use Any, that would usually be a better approach.

I would expect Any to work in most situations where you've got a collection of items to potentially match against... the non-Any approach is approprate for "in some situations, anyone over 18 is fine... in some situations anyone with a last name beginning with "G" is appropriate, etc.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • 1
    While this does answers this specific scenario, is there a more general approach? – sternr Aug 24 '11 at 18:22
  • That was my initial thought, but it gives me a stackoverflow exception as if predicate calls itself instead of the previous Func – sternr Aug 24 '11 at 18:29
  • @sternr: Um, yes - hang on, fixing... done. Now it'll capture a different variable for each iteration of the loop. Doh. – Jon Skeet Aug 24 '11 at 18:32
  • Ummm, this doesn't give an exception, but it doesnt work - it ignores someOtherCondition – sternr Aug 24 '11 at 18:38
  • @stern: It shouldn't... can you produce a short but complete example which shows that? – Jon Skeet Aug 24 '11 at 19:55
  • Is there not a problem with the general approach in the sense that it does not translate to SQL? `IQueryable.Where` accepts `Expression>`, `IEnumerable.Where` accepts `Func<>`, so passing a `Func<>` predicate results in fetching the entire table on the client and filtering it with the predicate instead of translating it to SQL, and declaring the `predicate` as `Expression>` also does not work because then it can't be called like `predicateCopy(user)`. – GSerg May 18 '19 at 09:25
  • @GSerg: Yes, this answer is only an answer to the question being asked, which was using LINQ to Objects. If you want a Queryable-based solution, you'd need a slightly different approach. (There's a utility class somewhere that does this, but I can't remember what it's called now...) – Jon Skeet May 18 '19 at 09:47