Efcore: Using EF.Functions.Like in expressions doesnt work

Created on 25 Aug 2017  路  2Comments  路  Source: dotnet/efcore

In my EF 1.1 codebase I was constructing LIKE searches dynamically, give a list of public properties of type string of some POCO, and a list of search terms. It built an expression using Contains, something like below.

```C#

public static IQueryable SearchQuery(this IQueryable query, PagedResultsRequestDTO request, params Expression>[] stringProperties)
{
var containsMethod = typeof(string).GetMethod("Contains", new[] { typeof(string), typeof(string) });
var parameter = Expression.Parameter(typeof(T), "c");

var searchKeyParts = request.Searches
                ?.SelectMany(i => i
                    .Split(null)
                    .Where(j => !string.IsNullOrWhiteSpace(j)))
                .Distinct()
                .ToArray()
            ?? new string[] { };

var publicProperties = stringProperties.Select(i => i.Body
            .ToString()
            .Replace(i.Parameters[0].ToString() + ".", "")).ToList();

Expression andExpressions = Expression.Equal(Expression.Constant(1), Expression.Constant(1));

foreach (var searchKeyPart in searchKeyParts)  {
  Expression orExpressions = Expression.Equal(Expression.Constant(1), Expression.Constant(0));

  foreach (var property in publicProperties)  {
    Expression nameProperty = parameter;
if (property.Contains("."))
{
  var props = new Queue<string>(property.Split('.'));
  while (props.Count > 0)  {
    var p = props.Dequeue();
    nameProperty = Expression.Property(nameProperty, p);
  }
}
else    {
  nameProperty = Expression.Property(parameter, property);
}

    Expression searchKeyExpression = Expression.Constant(searchKeyPart);
    Expression callContainsMethod = Expression.Call(nameProperty, containsMethod, searchKeyExpression);
    orExpressions = Expression.OrElse(orExpressions, callContainsMethod);                        
  }
    andExpressions = Expression.AndAlso(andExpressions, orExpressions);
}

var whereCallExpression = Expression.Call(
          typeof(Queryable),
          "Where",
          new[] { query.ElementType },
          query.Expression,
          Expression.Lambda<Func<T, bool>>(andExpressions, parameter));

query = request.Searches != null && request.Searches.Any()
? query.Provider.CreateQuery(whereCallExpression)
: query;

 In 2.0 this stopped working. I tried to use EF.Functions.Like in the same way, but

```C#
var likeMethod = typeof(DbFunctions).GetMethod("Like", new[] { typeof(string),  typeof(string) });

Returns null - some compiler magic here? Looking at the source code, DbFunctions is empty.

How do I use EF.Functions.Like if I am building a query expression manually?

closed-question

Most helpful comment

I ran into a similar issue and used the following:

var likeMethod = typeof(DbFunctionsExtensions).GetMethod("Like", new[] { typeof(DbFunctions), typeof(string), typeof(string) });

Then use something like:

Expression.Call(null, likeMethod, Expression.Constant(EF.Functions), searchKeyExpression, Expression.Constant($"%{filter.Value}"));

"Like" is an extension and needs to be called differently.

All 2 comments

I ran into a similar issue and used the following:

var likeMethod = typeof(DbFunctionsExtensions).GetMethod("Like", new[] { typeof(DbFunctions), typeof(string), typeof(string) });

Then use something like:

Expression.Call(null, likeMethod, Expression.Constant(EF.Functions), searchKeyExpression, Expression.Constant($"%{filter.Value}"));

"Like" is an extension and needs to be called differently.

Thanks Homertax.

Was this page helpful?
0 / 5 - 0 ratings