Answers for "How to use to support the Contains, StartsWith and EndsWith operations with LINQ Expression"

C#
0

How to use to support the Contains, StartsWith and EndsWith operations with LINQ Expression

// sample expression to generate dynamically
p => (p.Id >= 2 && p.Id <= 4)
    && (p.Birth != null p.Birth.Country != null)
    && p.Contacts.Any(c => c.Value.EndsWith("@email.com")
    || (p.Name != null && p.Name.Trim().ToLower().Contains("john")))

// This is how the code is used
var filter = new Filter<Person>();
filter.By("Id", Operation.Between, 2, 4)
      .And.By("Birth.Country", Operation.IsNotNull)
      .And.By("Contacts[Value]", Operations.EndsWith, "@email.com")
      .Or.By("Name", Operaions.Contains, " John");


static MethodInfo containsMethod = typeof(string).GetMethod("Contains");
static MethodInfo startsWithMethod = typeof(string)
    .GetMethod("StartsWith", new [] { typeof(string) });
static MethodInfo endsWithMethod = typeof(string)
    .GetMethod("EndsWith", new [] { typeof(string) });

//We need to add the Trim and ToLower MethodInfos
static MethodInfo trimMethod = typeof(string).GetMethod("Trim", new Type[0]);
static MethodInfo toLowerMethod = typeof(string).GetMethod("ToLower", new Type[0]);

public Expression<Func<TClass, bool>> BuildExpression()
{
    //this is in case the list of statements is empty
    Expression finalExpression = Expression.Constant(true);
    var parameter = Expression.Parameter(typeof(TClass), "x");
    var connector = FilterStatementConnector.And;
    foreach (var statement in Statements)
    {
        var member = GetMemberExpression(parameter, statement.PropertyName);
        var constant = Expression.Constant(statement.Value);
        
        if (statement.Value is string)
        {
            // x.Name.Trim()
            var trimMemberCall = Expression.Call(member, trimMethod);
            // x.Name.Trim().ToLower()
            member = Expression.Call(trimMemberCall, toLowerMethod);
            // "John ".Trim()
            var trimConstantCall = Expression.Call(constant, trimMethod); 
            // "John ".Trim().ToLower()
            constant = Expression.Call(trimConstantCall, toLowerMethod); 
        }
        
        var expression = Expressions[statement.Operation].Invoke(member, constant);
        finalExpression = CombineExpressions(finalExpression, expression, connector);
        connector = statement.Connector;
    }
    
    return finalExpression;
}

Expression CombineExpressions(Expression expr1,
    Expression expr2, FilterStatementConnector connector)
{
    return connector == FilterStatementConnector.And ? 
			Expression.AndAlso(expr1, expr2) : Expression.OrElse(expr1, expr2);
}

MemberExpression GetMemberExpression(Expression param, string propertyName)
{
    if (propertyName.Contains("."))
    {
        int index = propertyName.IndexOf(".");
        var subParam = Expression.Property(param, propertyName.Substring(0, index));
        return GetMemberExpression(subParam, propertyName.Substring(index + 1));
    }
    
    return Expression.Property(param, propertyName);
}
Posted by: Guest on August-25-2021

Code answers related to "How to use to support the Contains, StartsWith and EndsWith operations with LINQ Expression"

C# Answers by Framework

Browse Popular Code Answers by Language