2010-02-19 16 views
9

Bien, supongo que esto ya se ha respondido en alguna parte, y aún no estoy suficientemente familiarizado con la sintaxis que tengo que entender, así que tengan paciencia conmigo.Construir dinámicamente la expresión de Linq Lambda

Los usuarios de mi aplicación web deben filtrar una larga lista de elementos en una vista de cuadrícula, a la que se accede a través de un linqdatasource. Estoy usando el Evento OnSelecting para filtrar más elementos. Quiero filtrar esos elementos según las selecciones que hagan los usuarios en DropDownLists.

Por ejemplo, seleccione "Título" "Contiene" "Fred" Esto se traduce en

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

O "Descripción" "no contiene" "Alpha" resultados en

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

Me gustaría construir esa Expresión (System.Linq.Expressions.Expression>) dinámicamente, en lugar de tener expresiones de cambio anidadas para generarlo, ya que hay una cantidad de campos que quiero verificar, y también quiero usar el StartsWith y EndsWith check s. Si pudiera construir la expresión como una cadena, así:

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

Y entonces de alguna manera tener que ser convertida en una expresión ... ¿es esto posible? ¿O debería simplemente morder la viñeta y generar todas las declaraciones switch() requeridas para crear las diversas expresiones?

+0

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

Respuesta

8

Sin duda podría construir la expresión de forma dinámica, pero consideraría utilizar primero el Dynamic LINQ como alternativa, aunque es posible que no pueda usar Contiene. Además, es posible que desee considerar usar PredicateBuilder para crear consultas complejas de forma aditiva.

+0

Acepto usar la biblioteca Dynamic Linq. Un feo grande funcionará hoy, pero será más difícil de mantener/administrar en el futuro. –

+0

Dynamic Linq funciona perfectamente. Incluso maneja Field.Contains y! Field.Contains. Lo cual es bueno, porque no puedo hacer cara o cruz de PredicateBuilder. – Dave

+0

¿Debo descargar algo para obtener PredicateBuilder en vs210 .net4.0? – guiomie

4

probar este código ...

llamada al método 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); 
    } 
Cuestiones relacionadas