none
Linq Where dinâmico RRS feed

  • Pergunta

  • Estou tentando fazer um filtro numa pesquisa, tenho um textbox onde o usuário pode digitar ou não um nome de um produto se ele digitar faço um filtro se não digitar retorno uma lista com todos os produtos, fiz o seguinte código 

    ormDataContext dc = new ormDataContext();
                dc.ObjectTrackingEnabled = false;
    
                var q = (from o in dc.GetTable<ProdORM>()
                        select (new Prod
                        {
                            Codigo = o.Codigo,
                            Nome = o.Nome
                        }));
    
                if (!String.IsNullOrEmpty(search_criteria))
                    q = q.Where(o => o.Nome.Contains(search_criteria));
    
                return q.AsQueryable<Prod>();

    A query funciona o problema é que quando o usuário digita um texto para buscar o produto ele primeiro retornar uma lista com todos os produtos e só depois aplica o filtro

    q = q.Where(o => o.Nome.Contains(search_criteria));

    Gostaria de saber se teria como aplicar dinamicamente esse filtro sem que ele retorno com tudo do banco pra depois aplicar o filtro.


    Damon Abdiel

    quarta-feira, 22 de abril de 2015 13:48

Respostas

  • Damon, tive o mesmo problema que você. Consegui resolver parcialmente da seguinte forma:

        public class ParameterRebinder : ExpressionVisitor
        {
            private readonly Dictionary<ParameterExpression, ParameterExpression> map;
    
            public ParameterRebinder(Dictionary<ParameterExpression, ParameterExpression> map)
            {
                this.map = map ?? new Dictionary<ParameterExpression, ParameterExpression>();
            }
    
            public static Expression ReplaceParameters(Dictionary<ParameterExpression, ParameterExpression> map, Expression exp)
            {
                return new ParameterRebinder(map).Visit(exp);
            }
    
            protected override Expression VisitParameter(ParameterExpression p)
            {
                ParameterExpression replacement;
                if (map.TryGetValue(p, out replacement))
                {
                    p = replacement;
                }
                return base.VisitParameter(p);
            }
        }

    public class static Utils
    {
    
            public static Expression<T> Compose<T>(this Expression<T> first, Expression<T> second, Func<Expression, Expression, Expression> merge)
            {
                // build parameter map (from parameters of second to parameters of first)
                var map = first.Parameters.Select((f, i) => new { f, s = second.Parameters[i] }).ToDictionary(p => p.s, p => p.f);
    
                // replace parameters in the second lambda expression with parameters from the first
                var secondBody = ParameterRebinder.ReplaceParameters(map, second.Body);
    
                // apply composition of lambda expression bodies to parameters from the first expression 
                return Expression.Lambda<T>(merge(first.Body, secondBody), first.Parameters);
            }
    
            public static Expression<Func<T, bool>> And<T>(this Expression<Func<T, bool>> first, Expression<Func<T, bool>> second)
            {
                return first.Compose(second, Expression.And);
            }
    
            public static Expression<Func<T, bool>> Or<T>(this Expression<Func<T, bool>> first, Expression<Func<T, bool>> second)
            {
                return first.Compose(second, Expression.Or);
            }
    }

    public List<T> RetornarConsulta(string t1, string t2)
    {
      Expression<Func<T, bool>> expr1 = null;
      Expression<Func<T, bool>> expr2 = null;
      Expression<Func<T, bool>> expression = null;
      if(t1!=null)
      {
         expr1 = e => e.CAMPO1.Equals(t1);
         expression = expr1;
      }
      if(t2!=null)
      {
         expr2 = e => e.CAMPO2.Equals(t2);
         if(expression == null)
         {
            expression = expr2;
         }
         else
         {
            expression = expression.Or(expr2);
         }
      }
    
      ormDataContext dc = new ormDataContext();
      dc.Set<T>.Where(expression).ToList<T>();
    }

    quarta-feira, 22 de abril de 2015 14:17

Todas as Respostas

  • Damon, 

    Eu faria assim :

    string nome = txt.pesqnome.text;

    if (!String.IsnullorEmpty(nome))

    {

        faz a pesquisa com o nome;

    }

    else

    {

        faz a pesquisa com todos;

    }


    Junior



    • Editado Junior_luiz quarta-feira, 22 de abril de 2015 13:52
    quarta-feira, 22 de abril de 2015 13:51
  • Também pensei nisso.

    Mas fiquei na esperança de ter alguma coisa mais dinâmica 

    digamos que tivesse um cenário com mais filtros ficaria meio complicado fazer as buscas


    Damon Abdiel

    quarta-feira, 22 de abril de 2015 13:55
  • Damon, tive o mesmo problema que você. Consegui resolver parcialmente da seguinte forma:

        public class ParameterRebinder : ExpressionVisitor
        {
            private readonly Dictionary<ParameterExpression, ParameterExpression> map;
    
            public ParameterRebinder(Dictionary<ParameterExpression, ParameterExpression> map)
            {
                this.map = map ?? new Dictionary<ParameterExpression, ParameterExpression>();
            }
    
            public static Expression ReplaceParameters(Dictionary<ParameterExpression, ParameterExpression> map, Expression exp)
            {
                return new ParameterRebinder(map).Visit(exp);
            }
    
            protected override Expression VisitParameter(ParameterExpression p)
            {
                ParameterExpression replacement;
                if (map.TryGetValue(p, out replacement))
                {
                    p = replacement;
                }
                return base.VisitParameter(p);
            }
        }

    public class static Utils
    {
    
            public static Expression<T> Compose<T>(this Expression<T> first, Expression<T> second, Func<Expression, Expression, Expression> merge)
            {
                // build parameter map (from parameters of second to parameters of first)
                var map = first.Parameters.Select((f, i) => new { f, s = second.Parameters[i] }).ToDictionary(p => p.s, p => p.f);
    
                // replace parameters in the second lambda expression with parameters from the first
                var secondBody = ParameterRebinder.ReplaceParameters(map, second.Body);
    
                // apply composition of lambda expression bodies to parameters from the first expression 
                return Expression.Lambda<T>(merge(first.Body, secondBody), first.Parameters);
            }
    
            public static Expression<Func<T, bool>> And<T>(this Expression<Func<T, bool>> first, Expression<Func<T, bool>> second)
            {
                return first.Compose(second, Expression.And);
            }
    
            public static Expression<Func<T, bool>> Or<T>(this Expression<Func<T, bool>> first, Expression<Func<T, bool>> second)
            {
                return first.Compose(second, Expression.Or);
            }
    }

    public List<T> RetornarConsulta(string t1, string t2)
    {
      Expression<Func<T, bool>> expr1 = null;
      Expression<Func<T, bool>> expr2 = null;
      Expression<Func<T, bool>> expression = null;
      if(t1!=null)
      {
         expr1 = e => e.CAMPO1.Equals(t1);
         expression = expr1;
      }
      if(t2!=null)
      {
         expr2 = e => e.CAMPO2.Equals(t2);
         if(expression == null)
         {
            expression = expr2;
         }
         else
         {
            expression = expression.Or(expr2);
         }
      }
    
      ormDataContext dc = new ormDataContext();
      dc.Set<T>.Where(expression).ToList<T>();
    }

    quarta-feira, 22 de abril de 2015 14:17
  •  

    O exemplo abaixo resolve seu problema, se for null busca tudo se não for nulo testa a condição.

    q = q.Where(o => string.IsNullOrEmpty(search_criteria) || o.Nome.Contains(search_criteria));

    quarta-feira, 22 de abril de 2015 14:25
  •  

    O exemplo abaixo resolve seu problema, se for null busca tudo se não for nulo testa a condição.

    q = q.Where(o => string.IsNullOrEmpty(search_criteria) || o.Nome.Contains(search_criteria));

    Cesar isso cai no mesmo problema que eu relatei no inicio do post ele pra fazer esse filtro retorna todos os registro e depois efetua o filtro, quando o usuário quiser pesquisar por nome ou código ele vai "teoricamente" fazer duas consultas uma retornando todos os registro e depois outra aplicando esse filtro.

    Damon Abdiel


    quarta-feira, 22 de abril de 2015 16:29
  • Alexandre 

    Perfeito essa solução, alem de resolver esse problema acabou solucionando um outro que eu tinha quando queria fazer uma pesquisa com vários parâmetros diferentes.

    Meu código ficou da seguinte forma:

    ormDataContext dc = new ormDataContext();
                dc.ObjectTrackingEnabled = false;
                Expression<Func<Prod, bool>> expression = null;
                Expression<Func< Prod, bool>> exprNome = null;
                Expression<Func< Prod, bool>> exprCodigo = null;
    
                if (!String.IsNullOrEmpty(search_criteria))
                {
                    exprNome = e => e.Nome.Contains(search_criteria);
                    expression = exprNome;
                }
    
    
                if (!String.IsNullOrEmpty(search_criteria))
                {
                    exprCodigo = e => e.Codigo.ToString().Equals(search_criteria);
                    if (expression == null)
                        expression = exprCodigo;
                    else
                        expression = expression.Or(exprCodigo);
                }
    
                if (String.IsNullOrEmpty(search_criteria))
                {
                    var q = (from o in dc.GetTable<ProdORM>()
                             select (new Prod
                             {
                                 Codigo = o.Codigo,
                                 Nome = o.Nome
                             }));
    
                    return q.AsQueryable< Prod >();
                }
                else
                {
                    var q = (from o in dc.GetTable<ProdORM>()
                             select (new Prod
                             {
                                 Codigo = o.Codigo,
                                 Nome = o.Nome
                             })).Where(expression);
    
                    return q.AsQueryable< Prod >();
                }

    O único problema foi quando for buscar em branco (retornar todos os registros) nesse caso utilizei um If mas com essa solução que vc propôs não importa quantos parâmetros o método terá apenas um If.

    Só pra referencias futuras segue link do artigo que aborda a solução: http://blogs.msdn.com/b/meek/archive/2008/05/02/linq-to-entities-combining-predicates.aspx

    Novamente obrigado Alexandre!


    Damon Abdiel


    quarta-feira, 22 de abril de 2015 16:35