title: Creating a dynamic EF filter that builds a LINQ Where equals/contains statement for any string entity property
body: <p>In short, I'm looking to do <a href="https://stackoverflow.com/questions/19654754/is-there-a-way-to-parameterize-method-in-a-linq-query">what this guy did</a>, but with Entity Framework 6.</p>
  
  <p>Implementing the proposed solution results in the error <strong>"The LINQ expression node type 'Invoke' is not supported in LINQ to Entities."</strong> Since the proposed solution uses <code>Invoke</code>, this is obviously an issue.</p>
  
  <p>I understand that there's a way to harness <a href="https://stackoverflow.com/a/12755768/3986790">a custom Compose method</a> to rewrite the expression tree without using <code>Invoke</code>, but I can't seem to wrap my head around it.</p>
  
  <p>Here's what I'm trying to write.</p>
  
  <p>I build an <code>IQueryable&lt;TEntity&gt;</code> dynamically using a <code>QueryParameters</code> object that's just a bag of properties to use for the WHERE clauses. <code>TEntity</code> is a standard code-first EF entity with data annotations all over the place. The query contruction looks something like this:</p>
  
  
  
  <pre class="lang-cs prettyprint-override"><code>IQueryable&lt;TEntity&gt; query = Context.Set&lt;TEntity&gt;();
  
  if (queryParams == null)
      return query;
  
  if (!string.IsNullOrWhiteSpace(queryParams.FirstName))
  {
      if (queryParams.ExactSearch)
      {
          query = query.Where(x =&gt; x.FirstName == queryParams.FirstName);
      }
      else
      {
          if (queryParams.PreferStartsWith)
          {
              query = query.Where(
                  x =&gt; x.FirstName.ToLower()
                      .StartsWith(
                          queryParams.FirstName
                              .ToLower()));
          }
          else
          {            
              query = query.Where(
                  x =&gt; x.FirstName.ToLower()
                      .Contains(
                          queryParams.FirstName
                              .ToLower()));
          }
      }
  }
  
  // ... repeat for all of queryParams' string props.
  // DateTime, int, bool, etc have their own filters.
  </code></pre>
  
  <p>This gets repeated for every query parameter for a string field to be queried. Obviously, this results in a lot of repeated code. I would love to be able to write a filter with a signature like this:</p>
  
  <pre class="lang-cs prettyprint-override"><code>public static IQueryable&lt;TEntity&gt; Search&lt;TEntity&gt;(
      this IQueryable&lt;TEntity&gt; query,
      Expression&lt;Func&lt;TEntity, string&gt;&gt; fieldExpression,
      string searchValue,
      bool exactSearch = true,
      bool useStartsWithOverContains = false) {...}
  </code></pre>
  
  <p>Which I can then consume like this:</p>
  
  <pre class="lang-cs prettyprint-override"><code>if (!string.IsNullOrWhiteSpace(queryParams.FirstName))
  {
      query = query.Search(
                  x =&gt; x.FirstName,
                  queryParams.FirstName,
                  queryParams.ExactSearch,
                  queryParams.PreferStartsWith);
  }
  </code></pre>
  
  <p>The closest I've come a definition for that extension method is the below, but as mentioned, it produces that "'Invoke' is not supported in LINQ to Entities" error:</p>
  
  <pre class="lang-cs prettyprint-override"><code>public static IQueryable&lt;TEntity&gt; Search&lt;TEntity&gt;(
      this IQueryable&lt;TEntity&gt; query,
      Expression&lt;Func&lt;TEntity, string&gt;&gt; fieldExpression,
      string searchValue,
      bool exactSearch = true,
      bool useStartsWithOverContains = false)
  {
      if (string.IsNullOrWhiteSpace(searchValue))
          return query;
  
      searchValue = searchValue.Trim();
  
      Expression&lt;Func&lt;TEntity, bool&gt;&gt; expression;
  
      if (exactSearch)
      {
          var x = Expression.Parameter(typeof(TEntity), "x");
  
          var left = Expression.Invoke(fieldExpression, x);
          var right = Expression.Constant(searchValue);
          var equalityExpression = Expression.Equal(left, right);
  
          expression = Expression.Lambda&lt;Func&lt;TEntity, bool&gt;&gt;(
              equalityExpression,
              x);
      }
      else
      {
          searchValue = searchValue.ToLower();
          var x = Expression.Parameter(typeof(TEntity), "x");
  
          var fieldToLower = Expression.Call(
              Expression.Invoke(fieldExpression, x),
              typeof(string).GetMethod(
                  "ToLower",
                  Type.EmptyTypes));
          var searchValueExpression =
              Expression.Constant(searchValue);
  
          var body = Expression.Call(
              fieldToLower,
              typeof(string).GetMethod(
                  useStartsWithOverContains ? "StartsWith" : "Contains",
                  new[] { typeof(string) }),
              searchValueExpression);
  
          expression = Expression.Lambda&lt;Func&lt;TEntity, bool&gt;&gt;(
              body,
              x);
      }
  
      return query.Where(expression);
  }
  </code></pre>
  
  <p>I started to include the <a href="https://stackoverflow.com/a/12207396/3986790">Compose method</a> I mentioned, but I got lost really quickly, and thus removed it.</p>
  
  <p>Open to any guidance! Thank you!</p>