Extension method returning lambda expression through compare

前端 未结 3 2014
情话喂你
情话喂你 2021-02-15 16:48

I\'m in the process of creating a more elaborate filtering system for this huge project of ours. One of the main predicates is being able to pass comparations through a string p

3条回答
  •  春和景丽
    2021-02-15 17:32

    To generate expression, that would be translated to SQL (eSQL) you should generate Expression manually. Here is example for GreaterThan filter creating, other filters can be made with similar technique.

    static Expression> CreateGreaterThanExpression(Expression> fieldExtractor, decimal value)
    {
        var xPar = Expression.Parameter(typeof(T), "x");
        var x = new ParameterRebinder(xPar);
        var getter = (MemberExpression)x.Visit(fieldExtractor.Body);
        var resultBody = Expression.GreaterThan(getter, Expression.Constant(value, typeof(decimal)));
        return Expression.Lambda>(resultBody, xPar);
    }
    
    private sealed class ParameterRebinder : ExpressionVisitor
    {
        private readonly ParameterExpression _parameter;
    
        public ParameterRebinder(ParameterExpression parameter)
        { this._parameter = parameter; }
    
        protected override Expression VisitParameter(ParameterExpression p)
        { return base.VisitParameter(this._parameter); }
    }
    

    Here is the example of usage. (Assume, that we have StackEntites EF context with entity set TestEnitities of TestEntity entities)

    static void Main(string[] args)
    {
        using (var ents = new StackEntities())
        {
            var filter = CreateGreaterThanExpression(x => x.SortProperty, 3);
            var items = ents.TestEnitities.Where(filter).ToArray();
        }
    }
    

    Update: For your creation of complex expression you may use code like this: (Assume have already made CreateLessThanExpression and CreateBetweenExpression functions)

    static Expression> CreateFilterFromString(Expression> fieldExtractor, string text)
    {
        var greaterOrLessRegex = new Regex(@"^\s*(?\>|\<)\s*(?\d+(\.\d+){0,1})\s*$");
        var match = greaterOrLessRegex.Match(text);
        if (match.Success)
        {
            var number = decimal.Parse(match.Result("${number}"));
            var sign = match.Result("${sign}");
            switch (sign)
            {
                case ">":
                    return CreateGreaterThanExpression(fieldExtractor, number);
                case "<":
                    return CreateLessThanExpression(fieldExtractor, number);
                default:
                    throw new Exception("Bad Sign!");
            }
        }
    
        var betweenRegex = new Regex(@"^\s*(?\d+(\.\d+){0,1})\s*-\s*(?\d+(\.\d+){0,1})\s*$");
        match = betweenRegex.Match(text);
        if (match.Success)
        {
            var number1 = decimal.Parse(match.Result("${number1}"));
            var number2 = decimal.Parse(match.Result("${number2}"));
            return CreateBetweenExpression(fieldExtractor, number1, number2);
        }
        throw new Exception("Bad filter Format!");
    }
    

提交回复
热议问题