2010-02-19 2 views
9

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

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

Например, они выбирают "Title" "Содержит", "Фред" Это приводит к

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

Или "Описание" "Не содержит" "Альфа" результаты в

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

Я хотел бы создать динамическое выражение Expression (System.Linq.Expressions.Expression>) вместо наличия вложенных выражений switch для его создания, так как есть несколько полей, которые я хочу проверить, и также хочу использовать Запускает и заканчивает с проверкой s. Если бы я мог построить выражение в виде строки, например так:

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

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

+0

http://stackoverflow.com/questions/1810808/linq-the-dynamic-query-or -how-to-get-a-unknown-number-of-columns – Luiscencio

ответ

8

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

+0

Я согласен использовать библиотеку Dynamic Linq. Сегодня большая уродливость будет работать, но сложнее поддерживать/управлять по дороге. –

+0

Динамический Linq работает отлично. Он даже обрабатывает Field.Contains and! Field.Contains. Это хорошо, потому что я не могу сделать головы или хвосты PredicateBuilder. – Dave

+0

Нужно ли загружать что-то, чтобы получить PredicateBuilder в vs210 .net4.0? – guiomie

4

попробовать этот код ...

вызов 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); 
    }