LINQ: Split Where OR conditions

2020-04-07 04:38发布

问题:

So I have the following where conditions

sessions = sessions.Where(y => y.session.SESSION_DIVISION.Any(x => x.DIVISION.ToUpper().Contains(SearchContent)) ||
                                                   y.session.ROOM.ToUpper().Contains(SearchContent) ||
                                                   y.session.COURSE.ToUpper().Contains(SearchContent));

I want to split this into multiple lines based on whether a string is empty for example:

if (!String.IsNullOrEmpty(Division)) {
    sessions = sessions.Where(y => y.session.SESSION_DIVISION.Any(x => x.DIVISION.ToUpper().Contains(SearchContent)));
}

if (!String.IsNullOrEmpty(Room)) {

    // this shoudl be OR
    sessions = sessions.Where(y => y.session.ROOM.ToUpper().Contains(SearchContent));
}

if (!String.IsNullOrEmpty(course)) {

    // this shoudl be OR
    sessions = sessions.Where(y => y.session.COURSE.ToUpper().Contains(SearchContent));
}

If you notice I want to add multiple OR conditions split based on whether the Room, course, and Division strings are empty or not.

回答1:

There are a few ways to go about this:

  1. Apply the "where" to the original query each time, and then Union() the resulting queries.

    var queries = new List<IQueryable<Session>>();
    if (!String.IsNullOrEmpty(Division)) {
        queries.Add(sessions.Where(y => y.session.SESSION_DIVISION.Any(x => x.DIVISION.ToUpper().Contains(SearchContent))));
    }
    
    if (!String.IsNullOrEmpty(Room)) {
    
        // this shoudl be OR
        queries.Add(sessions.Where(y => y.session.ROOM.ToUpper().Contains(SearchContent)));
    }
    
    if (!String.IsNullOrEmpty(course)) {
    
        // this shoudl be OR
        queries.Add(sessions.Where(y => y.session.COURSE.ToUpper().Contains(SearchContent)));
    }
    
    sessions = queries.Aggregate(sessions.Where(y => false), (q1, q2) => q1.Union(q2));
    
  2. Do Expression manipulation to merge the bodies of your lambda expressions together, joined by OrElse expressions. (Complicated unless you've already got libraries to help you: after joining the bodies, you also have to traverse the expression tree to replace the parameter expressions. It can get sticky. See this post for details.

  3. Use a tool like PredicateBuilder to do #2 for you.


回答2:

.Where() assumes logical AND and as far as I know, there's no out of box solution to do it. If you want to separate OR statements, you may want to look into using Predicate Builder or Dynamic Linq.



回答3:

You can create an extension method to conditionally apply the filter:

public static IQueryable<T> WhereIf<T>(
   this IQueryable<T> source, bool condition, 
   Expression<Func<T, bool>> predicate)
{
    return condition ? source.Where(predicate) : source;
}

And use it like this:

using static System.String;

...

var res = sessions
   .WhereIf(!IsNullOrEmpty(Division), y => y.session.SESSION_DIVISION.ToUpper().Contains(SearchContent))
   .WhereIf(!IsNullOrEmpty(Room), y => y.session.ROOM.ToUpper().Contains(SearchContent))
   .WhereIf(!IsNullOrEmpty(course), y => y.session.COURSE.ToUpper().Contains(SearchContent)));