Uso do LINQ com o controle GridView do ASP.NET - Parte 1
Renato Haddad
Microsoft MVP, MCT, MCPD e MCTS
Setembro 2009
Tecnologias: Visual Studio .NET 2008 SP1, ASP.NET 3.5 e LINQ
Sumário: Neste artigo vou mostrar um dos controles mais utilizados no ASP.NET, o GridView, o qual irá ser preenchido com dados oriundos de array e uma coleção (classe) através do LINQ
Conteúdo
Introdução
Porquê Linq?
Criação do Projeto
Conclusão
Referências + Tópicos Relacionados
Sobre o Autor
Introdução
O uso do controle GridView nas aplicações ASP.NET é muito comum, afinal é um dos melhores controles existentes no ASP.NET. Além da flexibilidade que o GridView oferece, a configuração do mesmo é simples e fácil de se associar a uma fonte de dados. Por outro lado, o uso do LINQ como fonte de dados do GridView tem se tornado uma das facilidades mais aplicáveis em projetos ASP.NET.
Para montar este exemplo abordado no artigo, você irá precisar do Visual Studio .NET 2008 com o SP1 instalado. O LINQ faz parte do .NET Framework 3.5 SP1 (Service Pack 1), portanto, se ainda não o tiver instalado, baixe do site de downloads da Microsoft e instale.
O público alvo são os desenvolvedores de aplicações ASP.NET.
Porquê LINQ?
O LINQ significa Language Integrated Query que é uma linguagem de consulta integrada que pode ser usado em qualquer tipo de consulta em coleções, seja em arrays, coleções com Generics (List<objeto> ou List(of objeto)), banco de dados através das classes de um modelo de objeto relacional (ORM). Isto significa dizer que você pode aplicar o LINQ nas aplicações existentes que utilizem o VS.NET 2008 SP1, basta que haja uma coleção.
Muitos desenvolvedores se enganam em não usar o LINQ porque acham que é somente para acesso a banco de dados, e este é o principal erro conceitual. Se você já desenvolve em camadas onde uma delas é a camada de acesso a dados (mais conhecida como DAL) e a mesma retorna uma coleção de objetos, então faça uso do LINQ imediatamente. No decorrer do artigo você irá perceber a facilidade que é implementá-lo.
Criação do projeto
Com o VS.NET 2008 aberto, crie um novo tipo de projeto (CTRL + SHIFT + N). Selecione a linguagem C#, o tipo de projeto Web, o template chamado ASP.NET Web Application (Figura 1). É este o modelo a ser usado, portanto, dê um nome para a aplicação, neste caso ArtigoLinqASPNET e informe qual o diretório será criado.
Figura 1 – Tipo de projeto
Clique no botão OK para criar o projeto. O formulário default.aspx já é criado automaticamente e podemos utilizá-lo para montar o exemplo. Monte um formulário com 3 botões (btnColecao, btnClasse e btnBanco) e 1 GridView chamado gridDados. Na Figura 2 você visualiza o design do formulário, sendo que o botão btnBanco será usado apenas na parte II deste artigo a ser publicado futuramente.
Figura 2 – Layout do formulário
Veja na Listagem 1 o código HTML referente ao layout padrão. Note que usei tags XHTML (fieldset e legend) para melhorar o layout e deixar executável em qualquer tipo de browser. O gridDados apliquei um formato para melhorar as cores.
<form id="form1" runat="server">
<div>
<fieldset>
<legend>Exemplo de LINQ com GridView</legend>
<br />
<asp:Button ID="btnColecao" runat="server" Text="Coleção" />
<asp:Button ID="btnClasse" runat="server" Text="Classe" />
<asp:Button ID="btnBanco" runat="server" Text="Banco de Dados" />
<br />
<asp:GridView ID="gridDados" runat="server" CellPadding="4" ForeColor="#333333" GridLines="None" >
<RowStyle BackColor="#F7F6F3" ForeColor="#333333" />
<PagerStyle BackColor="#284775" ForeColor="White" HorizontalAlign="Center" />
<HeaderStyle BackColor="#5D7B9D" Font-Bold="True" ForeColor="White" />
<AlternatingRowStyle BackColor="White" ForeColor="#284775" />
</asp:GridView>
</fieldset>
</div>
</form>
Listagem 1 – Código HTML gerado
O próximo passo é preencher o gridDados com um conjunto de informações oriundas de um array de string contendo a descrição de algumas linguagens. Para isto, dê um duplo clique no btnColecao e digite o seguinte código:
protected void btnColecao_Click(object sender, EventArgs e)
{
string[] linguagens = { "Visual C#", "Visual Basic", "Cobol", "Delphi", "Clipper"};
gridDados.DataSource = linguagens;
gridDados.DataBind();
}
Note que a fonte do gridDados.DataSource é o próprio array chamado linguagens. Até aqui, sem mistério, super simples. Pressione a tecla F5 para executar o formulário e visualizar o resultado. Óbvio que serão mostradas as linguagens do jeito que estão no array. Agora é que entra o LINQ.
Como faço para exibir as linguagens em ordem crescente? Qual será o código que você faria para isto? Experimente montar o seu código antes de olhar a minha solução com o LINQ. Muito bem, com o LINQ fica conforme o código a seguir. No LINQ você precisa informar as palavras chaves (from, in, orderby e select), sendo que é uma linguagem natural e de fácil entendimento. Que tal ler da seguinte forma: para cada linguagem (l) contida no array linguagens, classifique (orderby) pelo nome da linguagem (l) e, ao final, selecione (select) todas as linguagens (l). Viu como é fácil, com apenas uma linha é possível obter um excelente resultado.
gridDados.DataSource = from l in linguagens orderby l select l;
gridDados.DataBind();
Com o LINQ é tudo muito mais fácil, principalmente porque é uma linguagem natural. No entanto, existe outro recurso chamado expressão Lambda que torna o código muito mais curto, porém o grau de entendimento é maior. Costumo afirmar que você só dominará Lambda após 3 meses de uso constante, para poder entender a complexidade. Sendo assim, veja o mesmo resultado anterior com Lambda. Este código diz ao compilador o seguinte: pegue cada item do array linguagens e classifique-o em ordem crescente. O uso do l => l está dizendo ao compilador para aplicar o OrderBy em cada item da coleção.
gridDados.DataSource = linguagens.OrderBy(l => l);
Salve e execute no navegador para ver o resultado. Evoluindo um pouco mais este exemplo, como saber quais linguagens contém a palavra Visual no início do texto? Sei que pela sua experiência você já deve estar pensando em usar o IndexOf ou ainda montar um looping para varrer cada item da lista do array e fazer um IF para saber se o início contém a palavra esperada, certo? É exatamente isto, porém, com o LINQ é um pouco mais fácil. Veja o código que aplica a cláusula Where (onde) para cada item do array é avaliado se o início (StartsWith) contém o texto (Visual). Perceba novamente a linguagem natural das coisas, só apliquei um filtro com o Where.
gridDados.DataSource = from l in linguagens where l.StartsWith("Visual") select l;
Execute o projeto novamente para ver o resultado. E com a expressão Lambda, como ficaria este código? Veja a seguir o código usando Lambda. O where é aplicado diretamente à coleção e você apenas informou o filtro (l.Contains(“Visual”)). Internamente é a mesma coisa que dizer: a cada item da coleção, verifique se começa com o texto “Visual”. Mais uma vez, a Lambda não é de fácil entendimento, então, foque no LINQ e aos poucos vá evoluindo com Lambda. Veja na Figura 3 o resultado da execução desta expressão. E aí, o que acharam até aqui? Você me viu digitar alguma linha de SQL ANSI? Claro que não, e é por isto mesmo que precisamos divulgar o LINQ a todos os desenvolvedores.
gridDados.DataSource = linguagens.Where(l => l.Contains("Visual"));
Figura 3 – Resultado da execução do código
Agora vamos a um exemplo usando classe. No Solution Explorer, dê um clique com o botão direito no projeto e selecione Add / Class. Crie uma classe chamada atleta contendo três propriedades, sendo:
public class atleta
{
public string nome { get ; set; }
public int idade { get; set; }
public string modalidade { get; set; }
}
Pode salvar e fechar o código da classe. Agora no formulário default.aspx dê um duplo clique no botão btnClasse e crie uma coleção de atletas usando Generics. Veja o código na Listagem 2 o qual declaro o Generics com o List, informo o tipo atleta e o nome da lista chamada atletas. Para cada item da lista há uma declaração do atleta em si, ou seja, as propriedades do mesmo. Em seguida, a fonte de dados (DataSource) do gridDados é o nome da coleção atletas.
protected void btnClasse_Click(object sender, EventArgs e)
{
// define a lista de atletas com Generics
List<atleta> atletas = new List<atleta>()
{
new atleta { nome="Renato", idade=21, modalidade="kitesurf"},
new atleta { nome="Marc", idade=25, modalidade="kitesurf"},
new atleta { nome="Hilton", idade=30, modalidade="windsurf"},
new atleta { nome="Adrien", idade=34, modalidade="kitesurf"},
new atleta { nome="Claudio", idade=42, modalidade="windsurf"},
};
// preenche o grid com os atletas
gridDados.DataSource = atletas;
gridDados.DataBind();
}
Listagem 2 – Coleção de dados
Salve e execute para ver o resultado, conforme a Figura 4. Observe que a lista é mostrada de acordo com a entrada dos itens na lista. Aqui cabe uma observação em relação à montagem do GridView. A propriedade AutoGenerateColumns está como True, ou seja, o gridDados será preenchido com cada propriedade da lista.
Figura 4 – Lista de atletas
E agora, onde é que o LINQ entra? O melhor de tudo vem agora, pois se eu quiser exibir a lista de atletas em ordem crescente por modalidade, como faria? Tente pensar num código que você faria para depois comparar com o LINQ e Lambda. Com o LINQ, o código fica conforme a linha a seguir:
gridDados.DataSource = from a in atletas orderby a.modalidade select a;
Interpretando este código numa linguagem natural é o mesmo que dizer: para cada atleta contido na lista atletas, ordene-o pela propriedade modalidade e ao final, selecione-o. Viu como é simples listar os atletas com apenas uma linha!
E usando Lambda, como ficaria? Sem comentários, é muito fácil usar esta notação, certo? Nem sempre, mas com o tempo você irá se acostumar. Esta linha diz o seguinte: ordene todos os atletas pela modalidade. Execute o código e veja na Figura 5 o resultado.
gridDados.DataSource = atletas.OrderBy(a => a.modalidade);
Figura 5 – Lista de atletas em ordem por modalidade
Já que temos o LINQ e Lambda para nos ajudar, que tal listar somente os atletas da modalidade kitesurf ordenados em ordem crescente de nomes? Veja os códigos com LINQ e Lambda, vale a pena testar os dois. Cabe ressaltar que conforme você digita, o intellisense da classe (neste caso a) mostra todas as propriedades.
// LINQ
gridDados.DataSource = from a in atletas where a.modalidade.Equals("kitesurf") orderby a.nome select a;
// Lambda
gridDados.DataSource = atletas.Where(a => a.modalidade.Equals("kitesurf")).OrderBy(a => a.nome);
Figura 6 – Filtro de atletas em ordem de nome
Por fim, já que temos duas modalidades na lista de atletas, que tal colocarmos todas as modalidades existentes numa combobox e deixar que o internauta selecione quais atletas deverão ser exibidos de acordo com a modalidade selecionada!
Para isto, teremos que mudar o layout do formulário para inserir o controle dropdownList (dropModalidades) antes do gridDados. Veja na Figura 7 o dropModalidades inserido e configurado para Enable AutoPostBack = true. Isto é obrigatório para que seja disparada uma requisição ao servidor assim que a modalidade for selecionada.
Figura 7 – Novo layout com o dropdown
Agora a mudança se dará no código. Atualmente a lista de atletas está dentro do btnColecao e precisamos movê-la para logo após a declaração do partial class no início do arquivo. Isto é preciso para que a lista atletas seja acessada em qualquer parte deste código.
public partial class _Default : System.Web.UI.Page
{
// define a lista de atletas com Generics
List<atleta> atletas = new List<atleta>()
{
new atleta { nome="Renato", idade=21, modalidade="kitesurf"},
new atleta { nome="Marc", idade=25, modalidade="kitesurf"},
new atleta { nome="Hilton", idade=30, modalidade="windsurf"},
new atleta { nome="Adrien", idade=34, modalidade="kitesurf"},
new atleta { nome="Claudio", idade=42, modalidade="windsurf"},
};
}
Em seguida, no evento Page_Load, o qual ocorre quando a página é carregada, é preciso digitar o seguinte código para carregar o dropModalidades com todas as modalidades existentes na lista de atletas. Veja a seguir o código. Usei Lambda e há uma novidade chamada Distinct, o qual tem como finalidade não repetir os itens iguais, ou seja, lista somente os distintos. Esta parece uma palavra mágica, pois não é preciso fazer absolutamente nada no código, montar um looping para verificar se há itens iguais, etc.
O uso do !Page.IsPostBack faz com que o código inserido neste bloco seja executado apenas a primeira vez que a página é carregada e nunca mais. Resumindo, já temos a lista de modalidades listadas no dropdown assim que a página for carregada.
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
dropModalidades.DataSource = atletas.Select(a => a.modalidade).Distinct();
dropModalidades.DataBind();
}
}
O próximo passo é montar o código para listar somente os atletas da modalidade selecionada. Para isto, dê um duplo clique no dropModalidades e digite o seguinte código:
protected void dropModalidades_SelectedIndexChanged(object sender, EventArgs e)
{
// filtra os atletas da modalidade selecionada
gridDados.DataSource = atletas.Where(m => m.modalidade.Equals(dropModalidades.Text));
gridDados.DataBind();
}
Aparentemente tudo está perfeito, mas um pequeno ajuste no Page_Load deixará o código perfeito. Após o DataBind, adicione a linha que irá disparar o método que filtra os atletas, e como não é preciso passar nenhum parâmetro, use o null duas vezes. Isto fará com que assim que a página for carregada pela primeira vez, o dropModalidades é preenchido com a primeira modalidade e automaticamente o gridDados mostra os atletas da respectiva modalidade.
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
dropModalidades.DataSource = atletas.Select(a => a.modalidade).Distinct();
dropModalidades.DataBind();
dropModalidades_SelectedIndexChanged(null, null);
}
}
Salve o projeto e execute-o no navegador. A Figura 8 mostra a tela quando carregada pela primeira vez. Agora, cabe ao internauta selecionar outra modalidade e pronto.
Figura 8 – Atletas da modalidade
Enfim, neste artigo você pode observar como que o LINQ e Lambda nos ajudam na codificação, deixando o código muito mais simples, claro e de fácil manutenção. Praticamente eu não faço nenhum projeto hoje em dia que não use o LINQ e Lambda.
Conclusão
O LINQ é uma linguagem para dar produtividade ao time de desenvolvedores, tornando o tempo um fator a favor da criação e manutenção. Além disto, as linguagens dinâmicas num futuro próximo usarão estes recursos nos bastidores, ou seja, você não pode ficar fora desta onda fantástica.
Referências + Tópicos Relacionados
Livro LINQ e C# 3.0 – A Solução em Consultas para Desenvolvedores – Autor: Renato Haddad http://www.editoraerica.com.br/buscafinal.asp?cod=2366
DVDs de treinamentos de LINQ TO SQL, Crie uma aplicação ASP.Net com LINQ e LINQ Avançado disponíveis no www.renatohaddad.com
Sobre o Autor
Renato Haddad (rehaddad@msn.com – www.renatohaddad.com ) é MVP, MCT, MCPD e MCTS, palestrante em eventos da Microsoft em diversos países, ministra treinamentos focados em produtividade com o VS.NET 2008, ASP.NET 3.5, LINQ, Reporting Services e Windows Mobile. Visite o blog https://weblogs.asp.net/renatohaddad . Renato é autor do livro LINQ e C# 3.0 – A Solução em Consultas para Desenvolvedores.