title: EF Core dynamic filter
body: <p>I've been working in a Dynamic filter class for EF Core queries using Expression trees, everything looks good, filter is working, I can pass a filter collection and it works, but when I look at the SQL sentence, it is querying the whole table and applying the filter on the resulting collection, here is my class...</p>
  
  <pre><code>   public static class QueryExpressionBuilder
  {
      private static readonly MethodInfo ContainsMethod = typeof(string).GetMethod("Contains", new[] { typeof(string) });
      private static readonly MethodInfo StartsWithMethod = typeof(string).GetMethod("StartsWith", new[] { typeof(string) });
      private static readonly MethodInfo EndsWithMethod = typeof(string).GetMethod("EndsWith", new[] { typeof(string) });
  
      #region DynamicWhere
  
      /// &lt;summary&gt;Where expression generator.&lt;/summary&gt;
      /// &lt;typeparam name="T"&gt;&lt;/typeparam&gt;
      /// &lt;param name="filters"&gt;The filters.&lt;/param&gt;
      /// &lt;returns&gt;&lt;/returns&gt;
      public static Expression&lt;Func&lt;T, bool&gt;&gt; GetExpression&lt;T&gt;(IList&lt;Filter&gt; filters)
      {
          if (filters.Count == 0)
              return null;
  
          ParameterExpression param = Expression.Parameter(typeof(T), "t");
          Expression exp = null;
  
          if (filters.Count == 1)
              exp = GetExpression(param, filters[0]);
          else if (filters.Count == 2)
              exp = GetExpression&lt;T&gt;(param, filters[0], filters[1]);
          else
          {
              while (filters.Count &gt; 0)
              {
                  var f1 = filters[0];
                  var f2 = filters[1];
  
                  if (exp == null)
                      exp = GetExpression&lt;T&gt;(param, filters[0], filters[1]);
                  else
                      exp = Expression.AndAlso(exp, GetExpression&lt;T&gt;(param, filters[0], filters[1]));
  
                  filters.Remove(f1);
                  filters.Remove(f2);
  
                  if (filters.Count == 1)
                  {
                      exp = Expression.AndAlso(exp, GetExpression(param, filters[0]));
                      filters.RemoveAt(0);
                  }
              }
          }
  
          return Expression.Lambda&lt;Func&lt;T, bool&gt;&gt;(exp, param);
      }
  
      /// &lt;summary&gt;Comparision operator expression generator.&lt;/summary&gt;
      /// &lt;param name="param"&gt;The parameter.&lt;/param&gt;
      /// &lt;param name="filter"&gt;The filter.&lt;/param&gt;
      /// &lt;returns&gt;&lt;/returns&gt;
      private static Expression GetExpression(ParameterExpression param, Filter filter)
      {
          MemberExpression member = Expression.Property(param, filter.PropertyName);
          var type = member.Type;
          ConstantExpression constant;
          switch (type.Name)
          {
              case "Int32":
                  constant = Expression.Constant(Convert.ToInt32(filter.Value));
                  break;
              case "String":
              default:
                  constant = Expression.Constant(filter.Value);
                  break;
          }
  
          // ConstantExpression constant = Expression.Constant(filter.Value);
  
          switch (filter.Operation)
          {
              case Op.Equals:
                  return Expression.Equal(member, constant);
  
              case Op.GreaterThan:
                  return Expression.GreaterThan(member, constant);
  
              case Op.GreaterThanOrEqual:
                  return Expression.GreaterThanOrEqual(member, constant);
  
              case Op.LessThan:
                  return Expression.LessThan(member, constant);
  
              case Op.LessThanOrEqual:
                  return Expression.LessThanOrEqual(member, constant);
  
              case Op.Contains:
                  return Expression.Call(member, ContainsMethod, constant);
  
              case Op.StartsWith:
                  return Expression.Call(member, StartsWithMethod, constant);
  
              case Op.EndsWith:
                  return Expression.Call(member, EndsWithMethod, constant);
          }
  
          return null;
      }
  
      /// &lt;summary&gt;And logic connector expression generator.&lt;/summary&gt;
      /// &lt;typeparam name="T"&gt;&lt;/typeparam&gt;
      /// &lt;param name="param"&gt;The parameter.&lt;/param&gt;
      /// &lt;param name="filter1"&gt;The filter1.&lt;/param&gt;
      /// &lt;param name="filter2"&gt;The filter2.&lt;/param&gt;
      /// &lt;returns&gt;&lt;/returns&gt;
      private static BinaryExpression GetExpression&lt;T&gt;(ParameterExpression param, Filter filter1, Filter filter2)
      {
          var bin1 = GetExpression(param, filter1);
          var bin2 = GetExpression(param, filter2);
  
          return Expression.AndAlso(bin1, bin2);
      }
  
      #endregion
  
  }
  </code></pre>
  
  <p>}</p>
  
  <p>To call this class I do something like this :</p>
  
  <pre><code>var whereDeleg = QueryExpressionBuilder.GetExpression&lt;Tax&gt;(filters).Compile();
  var myList = _dbContext.MyEntity.Where(whereDeleg).ToList();
  </code></pre>
  
  <p>The filters parameter i'm passing is a collection of this class :</p>
  
  <pre><code>public class Filter
  {
      public string PropertyName { get; set; }
      public Op Operation { get; set; }
      public object Value { get; set; }
  }
  </code></pre>
  
  <p>I'd appreciate any help.</p>