LINQ - Usando cláusulas dinâmicas em Consultas (Where)


A LINQ - Language Integrated Query - fornece uma linguagem de consulta que pode ser usada para simplificar a consulta a entidades e banco de dados.

Uma possível vantagem em usar a linguagem SQL seria a possibilidade que as instruções SQL possuem em serem criadas dinamicamente usando a concatenação de strings para montar a instrução de consulta usando cláusulas Where.

Ocorre que a LINQ pode realizar a mesma tarefa sem a necessidade de concatenar strings.

Para mostrar este recurso da LINQ vamos iniciar criando um projeto no Visual C# 2010 Express Edition do tipo Windows Forms Application com o nome Consultas_LINQ_Where;

No formulário padrão form1.cs vamos incluir a partir da ToolBox um controle DataGridView (gdvDados) , dois controles Button (btnConsulta e btnSair), um controle TextBox (txtCriterio) , 4 controles RadioButton (rdbTitulo, rdbDescricao, rdbPaginas e rdbPopularidade) e um controle CheckBox (chkOrdem) conforme o leiaute da figura abaixo:

Vamos definir um classe Livro e uma lista genérica de livros ListaLivros que serão usadas como fonte de dados para realizarmos as consultas LINQ.

O código para a classe Livro é dado a seguir:

public class Livro

{

   public string Titulo { get; set; }

   public string Descricao { get; set; }

   public int Paginas { get; set; }

   public double Popularidade { get; set; }

}

A seguir no início do formulário form1.cs vamos definir a lista genérica ListaLivros que criará uma coleção do tipo Livro em memória.

    List<Livro> ListaLivros = new List<Livro> {
               new Livro { Titulo = "ASP, ADO Banco de dados na Web", Descricao = "Usando banco de dados com ASP",Paginas = 200, Popularidade = 7.5},
               new Livro { Titulo = "A Programmer’s Guide to ADO.NET in C#",Descricao = "A guide to ADO .NET using C#",Paginas = 290,Popularidade = 8.0},
               new Livro { Titulo = "Essential ADO.NET",Descricao = "Essential ADO .NET concepts in practice",Paginas = 350,Popularidade = 6.5},
               new Livro { Titulo = "Microsoft Visual Basic 2010 Step by Step",Descricao = "A complete reference guide to Visual Basic",Paginas = 437,Popularidade = 8.5 }
            };

Vamos definir a seguir o código do evento Click do botão Consultar:

   private void btnConsultar_Click(object sender, EventArgs e)
        {
            var consulta = from lv in ListaLivros select new { lv.Titulo, lv.Descricao, lv.Paginas, lv.Popularidade };
            if (rdbTitulo.Checked)
            {
                if (txtCriterio.Text != "")
                {
                    consulta = consulta.Where(livro => livro.Titulo.Contains(txtCriterio.Text));
                    OrdernarPeloCampo = "Titulo";
                }
            }
            if (rdbDescricao.Checked)
            {
                if (txtCriterio.Text != "")
                {
                    consulta = consulta.Where(livro => livro.Descricao.Contains(txtCriterio.Text));
                    OrdernarPeloCampo = "Descricao";
                }
            }
            if (rdbPaginas.Checked)
            {
                if (txtCriterio.Text != "")
                {
                    int pag = Convert.ToInt32(txtCriterio.Text);
                    consulta = consulta.Where(livro => livro.Paginas >= pag);
                    OrdernarPeloCampo = "Paginas";
                }
            }
            if (rdbPopularidade.Checked)
            {
                if (txtCriterio.Text != "")
                {
                    double pop = Convert.ToDouble(txtCriterio.Text);
                    consulta = consulta.Where(livro => livro.Popularidade >= pop);
                    OrdernarPeloCampo = "Popularidade";
                }
            }
            if (chkOrdem.Checked)
            {
                switch (OrdernarPeloCampo)
                {
                    case "Titulo":
                        consulta = consulta.OrderBy(livro => livro.Titulo);
                        break;
                    case "Descricao":
                        consulta = consulta.OrderBy(livro => livro.Descricao);
                        break;
                    case "Paginas":
                        consulta = consulta.OrderBy(livro => livro.Paginas);
                        break;
                    case "Popularidade":
                        consulta = consulta.OrderBy(livro => livro.Popularidade);
                        break;
                }
            }
            else
            {
                switch (OrdernarPeloCampo)
                {
                    case "Titulo":
                        consulta = consulta.OrderByDescending(livro => livro.Titulo);
                        break;
                    case "Descricao":
                        consulta = consulta.OrderByDescending(livro => livro.Descricao);
                        break;
                    case "Paginas":
                        consulta = consulta.OrderByDescending(livro => livro.Paginas);
                        break;
                    case "Popularidade":
                        consulta = consulta.OrderByDescending(livro => livro.Popularidade);
                        break;
                }
            }
            dgvDados.DataSource = consulta.ToList();
        }

 

No início definimos a consulta base :

            var consulta = from lv in ListaLivros select new { lv.Titulo, lv.Descricao, lv.Paginas, lv.Popularidade };

sobre a qual iremos montar de forma dinâmica a cláusula Where conforme o critério definido nas opções oferecidas nos radiobuttons do formulário.

A seguir fazemos exatamente isso :

    if (rdbTitulo.Checked)
            {
                if (txtCriterio.Text != "")
                {
                    consulta = consulta.Where(livro => livro.Titulo.Contains(txtCriterio.Text));
                    OrdernarPeloCampo = "Titulo";
                }
            }
            if (rdbDescricao.Checked)
            {
                if (txtCriterio.Text != "")
                {
                    consulta = consulta.Where(livro => livro.Descricao.Contains(txtCriterio.Text));
                    OrdernarPeloCampo = "Descricao";
                }
            }
            if (rdbPaginas.Checked)
            {
                if (txtCriterio.Text != "")
                {
                    int pag = Convert.ToInt32(txtCriterio.Text);
                    consulta = consulta.Where(livro => livro.Paginas >= pag);
                    OrdernarPeloCampo = "Paginas";
                }
            }
            if (rdbPopularidade.Checked)
            {
                if (txtCriterio.Text != "")
                {
                    double pop = Convert.ToDouble(txtCriterio.Text);
                    consulta = consulta.Where(livro => livro.Popularidade >= pop);
                    OrdernarPeloCampo = "Popularidade";
                }
            }

Verificamos qual a opção escolhida e checamos se o TextBox referente ao critério foi preenchido para montar a consulta apropriada acrescentando a cláusula Where;

Ao final antes de exibirmos o resultados verificamos se o Checkbox referente a ordem de exibição foi marcado ou não para acrescentarmos à consulta a cláusula OrderBy definindo a ordenação selecionada;

           if (chkOrdem.Checked)
            {
                switch (OrdernarPeloCampo)
                {
                    case "Titulo":
                        consulta = consulta.OrderBy(livro => livro.Titulo);
                        break;
                    case "Descricao":
                        consulta = consulta.OrderBy(livro => livro.Descricao);
                        break;
                    case "Paginas":
                        consulta = consulta.OrderBy(livro => livro.Paginas);
                        break;
                    case "Popularidade":
                        consulta = consulta.OrderBy(livro => livro.Popularidade);
                        break;
                }
            }
            else
            {
                switch (OrdernarPeloCampo)
                {
                    case "Titulo":
                        consulta = consulta.OrderByDescending(livro => livro.Titulo);
                        break;
                    case "Descricao":
                        consulta = consulta.OrderByDescending(livro => livro.Descricao);
                        break;
                    case "Paginas":
                        consulta = consulta.OrderByDescending(livro => livro.Paginas);
                        break;
                    case "Popularidade":
                        consulta = consulta.OrderByDescending(livro => livro.Popularidade);
                        break;
                }
            }

 

Finalmente exibimos o resultado no controle DataGridView:  dgvDados.DataSource = consulta.ToList();

Neste exemplo usamos as cláusulas Where e OrderBy para montar consultas de forma dinâmica mas podemos realizar outras operações de forma dinâmica com LINQ como Joins. Realizar Joins pode ser muito útil especialmente quando precisamos utilizar filtros dinâmicos.

É importante notar que a utilização do método para anexar cláusulas e tornar as consultas mais complexas não fará com que a consulta seja executada em cada etapa.

Para executar a consulta você precisará chamar uma operação ToList, ToArray,ToDictionary e percorrer os resultados ou qualquer um dos vários outros métodos que irá executar na consulta. Isto tem a vantagem de permitir a LINQ atrasar a execução tanto tempo quanto possível para reunir todos os filtros necessários e cláusulas orderby.

Pegue o projeto completo aqui: Consulta_LINQ_Where.zip

"Eu sou o Alfa e o Ômega, o princípio e o fim, o primeiro e o derradeiro.  Bem-aventurados aqueles que lavam as suas vestiduras no sangue do Cordeiro, para que tenha direito à árvore da vida, e possam entrar na cidade pelas portas." Apocalipse 22:13-14

Referências:


José Carlos Macoratti