Динамическое Построение Лямбда-Выражения Linq

хорошо, я предполагаю, что на это уже где-то ответили, и я просто недостаточно хорошо знаком с синтаксисом, чтобы понять, так что потерпите меня.

пользователям моего веб-приложения необходимо отфильтровать длинный список элементов в gridview, доступ к которому осуществляется через linqdatasource. Я использую событие OnSelecting для дальнейшего фильтрации элементов. Я хочу фильтровать эти элементы на основе выбора, который пользователи делают в раскрывающихся списках.

например, они выбирают "название ""содержит "" Фред" Этот результаты в

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

или "описание", "не содержит" "альфа" результаты в

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

Я хотел бы создать это выражение (System.В LINQ.Выражения.Expression>) динамически, вместо того, чтобы иметь вложенные выражения коммутатора для его генерации, поскольку есть несколько полей, которые я хочу проверить, и я также хочу использовать проверки StartsWith и EndsWith. Если бы я мог построить выражение в виде строки, например:

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

и тогда каким-то образом это будет преобразуется в выражение... возможно ли это? Или я должен просто укусить пулю и сгенерировать все операторы switch (), необходимые для создания различных выражений?

2 ответов


вы, безусловно, можете построить выражение динамически, но я бы рассмотрел использование динамические LINQ, которая в качестве альтернативы сначала, хотя вы не можете использовать Contains. Кроме того, вы можете рассмотреть возможность использования PredicateBuilder для построения сложных запросов аддитивно.


попробуйте этот код...

вызовите метод 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);
    }