Dynamically Build Linq Lambda Expression

2020-02-08 06:39发布

Okay, my guess is this is answered somewhere already, and I'm just not quite familiar enough with the syntax yet to understand, so bear with me.

The users of my web app need to filter a long list of items in a gridview, accessed via a linqdatasource. I am using the OnSelecting Event to further filter items. I want to filter those items based on selections the users make in DropDownLists.

For example, they select "Title" "Contains" "Fred" This results in

e.Result = dbContext.Opps.Where(opp => opp.Title.Contains("Fred"));

Or "Description" "Does not Contain" "Alpha" results in

 e.Result = dbContext.Opps.Where(opp => !opp.Description.Contains("Alpha"));

I would like to build up that Expression (System.Linq.Expressions.Expression>) dynamically, instead of having nested switch expressions to generate it, as there are a number of fields I want to check, and I also want to use the StartsWith and EndsWith checks. If I could build the Expression as a string, like so:

string stringExpression = string.Format("opp => opp.{0}.{1}(\"{2}\")",
    ddlCustomFilter.SelectedValue,
    ddlFilterType.SelectedValue,
    txtFilterText.Text);

And then somehow have it be converted into an Expression... is this possible? Or should I just bite the bullet and generate all the switch() statements required to create the various expressions?

标签: c# lambda
2条回答
再贱就再见
2楼-- · 2020-02-08 07:07

You could certainly build the expression dynamically, but I would consider using Dynamic LINQ as an alternative first, though you may not be able to use Contains. In addition, you may want to consider using PredicateBuilder to build complex queries additively.

查看更多
家丑人穷心不美
3楼-- · 2020-02-08 07:08

try this code...

call ToExpression Method()....

public static Expression<Func<T, bool>> ToExpression<T>(string andOrOperator, string propName, string opr, string value, Expression<Func<T, bool>> expr = null)
    {
        Expression<Func<T, bool>> func = null;
        try
        {
            ParameterExpression paramExpr = Expression.Parameter(typeof(T));
            var arrProp = propName.Split('.').ToList();
            Expression binExpr = null;
            string partName = string.Empty;
            arrProp.ForEach(x =>
            {
                Expression tempExpr = null;
                partName = partName.IsNull() ? x : partName + "." + x;
                if (partName == propName)
                {
                    var member = NestedExprProp(paramExpr, partName);
                    var type = member.Type.Name == "Nullable`1" ? Nullable.GetUnderlyingType(member.Type) : member.Type;
                    tempExpr = ApplyFilter(opr, member, Expression.Convert(ToExprConstant(type, value), member.Type));
                }
                else
                    tempExpr = ApplyFilter("!=", NestedExprProp(paramExpr, partName), Expression.Constant(null));
                if (binExpr != null)
                    binExpr = Expression.AndAlso(binExpr, tempExpr);
                else
                    binExpr = tempExpr;
            });
            Expression<Func<T, bool>> innerExpr = Expression.Lambda<Func<T, bool>>(binExpr, paramExpr);
            if (expr != null)
                innerExpr = (andOrOperator.IsNull() || andOrOperator == "And" || andOrOperator == "AND" || andOrOperator == "&&") ? innerExpr.And(expr) : innerExpr.Or(expr);
            func = innerExpr;
        }
        catch { }
        return func;
    }

    private static MemberExpression NestedExprProp(Expression expr, string propName)
    {
        string[] arrProp = propName.Split('.');
        int arrPropCount = arrProp.Length;
        return (arrPropCount > 1) ? Expression.Property(NestedExprProp(expr, arrProp.Take(arrPropCount - 1).Aggregate((a, i) => a + "." + i)), arrProp[arrPropCount - 1]) : Expression.Property(expr, propName);
    }

    private static Expression ToExprConstant(Type prop, string value)
    {
        if (value.IsNull())
            return Expression.Constant(value);
        object val = null;
        switch (prop.FullName)
        {
            case "System.Guid":
                val = value.ToGuid();
                break;
            default:
                val = Convert.ChangeType(value, Type.GetType(prop.FullName));
                break;
        }
        return Expression.Constant(val);
    }

    private static Expression ApplyFilter(string opr, Expression left, Expression right)
    {
        Expression InnerLambda = null;
        switch (opr)
        {
            case "==":
            case "=":
                InnerLambda = Expression.Equal(left, right);
                break;
            case "<":
                InnerLambda = Expression.LessThan(left, right);
                break;
            case ">":
                InnerLambda = Expression.GreaterThan(left, right);
                break;
            case ">=":
                InnerLambda = Expression.GreaterThanOrEqual(left, right);
                break;
            case "<=":
                InnerLambda = Expression.LessThanOrEqual(left, right);
                break;
            case "!=":
                InnerLambda = Expression.NotEqual(left, right);
                break;
            case "&&":
                InnerLambda = Expression.And(left, right);
                break;
            case "||":
                InnerLambda = Expression.Or(left, right);
                break;
            case "LIKE":
                InnerLambda = Expression.Call(left, typeof(string).GetMethod("Contains", new Type[] { typeof(string) }), right);
                break;
            case "NOTLIKE":
                InnerLambda = Expression.Not(Expression.Call(left, typeof(string).GetMethod("Contains", new Type[] { typeof(string) }), right));
                break;
        }
        return InnerLambda;
    }

    public static Expression<Func<T, object>> PropExpr<T>(string PropName)
    {
        ParameterExpression paramExpr = Expression.Parameter(typeof(T));
        var tempExpr = Extentions.NestedExprProp(paramExpr, PropName);
        return Expression.Lambda<Func<T, object>>(Expression.Convert(Expression.Lambda(tempExpr, paramExpr).Body, typeof(object)), paramExpr);

    }
    public static IQueryOver<T, T> OrderBy<T>(this IQueryOver<T, T> Collection, string sidx, string sord)
    {
        return sord == "asc" ? Collection.OrderBy(NHibernate.Criterion.Projections.Property(sidx)).Asc : Collection.OrderBy(NHibernate.Criterion.Projections.Property(sidx)).Desc;
    }

    public static Expression<Func<T, TResult>> And<T, TResult>(this Expression<Func<T, TResult>> expr1, Expression<Func<T, TResult>> expr2)
    {
        var invokedExpr = Expression.Invoke(expr2, expr1.Parameters.Cast<Expression>());
        return Expression.Lambda<Func<T, TResult>>(Expression.AndAlso(expr1.Body, invokedExpr), expr1.Parameters);
    }

    public static Expression<Func<T, bool>> Or<T>(this Expression<Func<T, bool>> expr1, Expression<Func<T, bool>> expr2)
    {
        var invokedExpr = Expression.Invoke(expr2, expr1.Parameters.Cast<Expression>());
        return Expression.Lambda<Func<T, bool>>(Expression.OrElse(expr1.Body, invokedExpr), expr1.Parameters);
    }
查看更多
登录 后发表回答