Dynamic query with OR conditions in Entity Framework

后端 未结 3 1955
我在风中等你
我在风中等你 2020-12-15 02:37

I am creating an application that searches the database and allows the user to dynamically add any criteria (around 50 possible), much like the following SO question: Creat

3条回答
  •  情书的邮戳
    2020-12-15 03:26

    Is there a simple and clean way to add "OR" conditions to a dynamically generated query using entity framework?

    Yes, you can achieve this by simply relying on a single where clause containing a single boolean expression whose OR parts are "disabled" or "enabled" dynamically at runtime, thus, avoiding having to install LINQKit or writing a custom predicate builder.

    In reference to your example:

    var isFirstValid = !string.IsNullOrWhiteSpace(first);
    var isLastValid = !string.IsNullOrWhiteSpace(last);
    
    var query = db.Names
      .AsQueryable()
      .Where(name =>
        (isFirstValid && name.first.Contains(first)) ||
        (isLastValid && name.last.Contains(last))
      )
      .ToList();
    

    As you can see in the example above, we are dynamically switching "on" or "off" the OR-parts of the where-filter expression based on previously evaluated premises (e.g isFirstValid).

    For example if isFirstValid is not true, then name.first.Contains(first) is short-circuited and will neither be executed nor affect the resultset. Moreover, EF Core's DefaultQuerySqlGenerator will further optimize and reduce the boolean expression inside where before executing it (e.g. false && x || true && y || false && z may be reduced to simply y through simple static analysis).

    Please note: If none of the premises are true, then the result-set will be empty – which I assume is the desired behavior in your case. However, if you for some reason rather prefer to select all elements from your IQueryable source, then you may add a final variable to the expression evaluating to true (e.g. .Where( ... || shouldReturnAll) with var shouldReturnAll = !(isFirstValid || isLastValid) or something similar).

    A final remark: The downside of this technique is that it forces you to build a "centralized" boolean expression that resides in the same method body in which your query lies (more precisely the where part of the query). If you, for some reason, want to decentralize the build process of your predicates and inject them as arguments or chain them via the query builder, then you should better stick with a predicate builder as suggested in the other answers. Otherwise, enjoy this simple technique :)

提交回复
热议问题