Expression.Like in C#

c# expression-trees sql-like

Question

eg: x=> x.Name = "g"

I have code block like this

public Expression<Func<TEntity, bool>> SearchExpression()
{
    var c = new ConstantExpression[_paramList.Count];
    var b = new BinaryExpression[_paramList.Count];
    BinaryExpression comparisonExpression = null;

    var entity = Expression.Parameter(typeof(TEntity));

    for (int i = 0; i < _paramList.Count; i++)
    {
        var value = Convert.ChangeType(_paramList[i].Item2 /*"g"*/, _paramList[i].Item3 /*System.String*/);
        c[i] = Expression.Constant(value); //"g"

        // PROBLEM IS HERE
        b[i] = Expression.Equal(Expression.Property(entity, _paramList[i].Item1 /*Name*/, c[i]);
        // PROBLEM IS HERE



    }
    _paramList.Clear();
    comparisonExpression = b.Aggregate(Expression.And);
    return Expression.Lambda<Func<TEntity, bool>>(comparisonExpression, entity);
}

works like charm but I need Expression.Like (Like "g" not Equal "g")

Expression.Like(Expression.Property(entity, _paramList[i].Item1), c[i])

but C# expression tree does not support Like method

UPDATE :

I wrote something like this :

Expression.Call(Expression.Property(entity, _paramList[i].Item1),
                typeof(String).GetMethod("Contains"), new Expression[] { c[i] });  

but I need BinaryExpression not MethodCallExpression

1
8
6/25/2014 10:08:58 AM

Accepted Answer

You can make your code work by adding an equals expression over the method call, like so:

    b[i] = Expression.Equal(
        Expression.Call(Expression.Property(entity, _paramList[i].Item1),
        typeof (String).GetMethod("Contains"), 
          new Expression[] {c[i]}), Expression.Constant(true));

In pseudo code this reads as:

b[i] = entity => entity.someProperty.Contains(c[i]) == true;

Which will return a binary expression for you.

4
6/25/2014 10:30:35 AM

Popular Answer

This answer does not consider your array and the 'and' aggregation, but this should be considered as a separate issue.

Consider this class:

class MyEntity { string Name { get; set; } }

We want to query:

select ... from MyEntity where Name like '%query%';

The following method is a general implementation of the above query pattern:

static Expression<Func<TEntity, bool>> Like<TEntity>(string propertyName, string queryText)
{
    var parameter = Expression.Parameter(typeof (TEntity), "entity");
    var getter = Expression.Property(parameter, propertyName);
    //ToString is not supported in Linq-To-Entities, throw an exception if the property is not a string.
    if (getter.Type != typeof (string))
        throw new ArgumentException("Property must be a string");
    //string.Contains with string parameter.
    var stringContainsMethod = typeof (string).GetMethod("Contains", new[] {typeof (string)});
    var containsCall = Expression.Call(getter, stringContainsMethod,
        Expression.Constant(queryText, typeof (string)));

    return Expression.Lambda<Func<TEntity, bool>>(containsCall, parameter);
}

If you want to have a pattern of query% or %query you can use string.StartsWith and string.EndsWith instead of Contains.

Also, you can share the parameter across multiple calls if you adjust the signature.

The current implementation throws an exception if the data type of the property is not a string. Look at this answer https://stackoverflow.com/a/3292773/668272 for converting numbers to strings.



Related Questions





Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow