代码之家  ›  专栏  ›  技术社区  ›  Dave

动态生成Linq lambda表达式

  •  11
  • Dave  · 技术社区  · 15 年前

    好吧,我猜这已经在某个地方得到了答案,我只是对语法还不太熟悉,还不能理解,所以请耐心等待。

    我的web应用程序的用户需要在一个通过linqdata源访问的gridview中过滤一长串项目。我正在使用OnSelecting事件进一步筛选项目。我想根据用户在DropDownlist中所做的选择筛选那些项目。

    例如,他们选择“标题”包含“fred” 这导致

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

    或“description”不包含“alpha” 结果在

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

    我希望动态构建该表达式(system.linq.expressions.expression>),而不是使用嵌套的switch表达式来生成它,因为有许多字段需要检查,我还希望使用startswith和endswith检查。如果我可以将表达式构建为字符串,比如:

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

    然后把它转化成一个表达式…这有可能吗?或者,我应该咬紧牙关生成创建各种表达式所需的所有switch()语句吗?

    2 回复  |  直到 15 年前
        1
  •  9
  •   tvanfosson    15 年前

    当然可以动态地构建表达式,但我会考虑使用 Dynamic LINQ 作为备选方案,首先,尽管您可能无法使用contains。此外,您可以考虑使用 PredicateBuilder 以添加方式构建复杂查询。

        2
  •  7
  •   suneelsarraf    11 年前

    尝试此代码…

    调用ToExpression方法()…

    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);
        }