ASP .NET MVC 3 - Ordenação, Filtragem e Paginação com EF - III
Este artigo é baseado no original: Creating an Entity Framework Data Model for an ASP.NET MVC Application (1 of 10) com adaptações e pequenos ajustes feitos por mim.
Antes de prosseguir verifique se você possui os seguintes recursos instalados:
Esta é terceira parte do artigo, e, você esta chegando agora deve ler obrigatoriamente as partes anteriores:
Neste artigo vamos abordar implementar a ordenação, filtragem e paginação dos dados usando o Entity Framework 4.1 e os recursos da ASP .NET MVC 3.
Implementando a Ordenação, Filtragem e Paginação
Abra o Visual Web Developer 2010 Express Edition e no menu File clique em Open Project; a seguir selecione o projeto que já foi criado no primeiro artigo com o nome UniversidadeMacoratti e clique em OK;
A estrutura do projeto exibida na janela Solution Explorer deverá ser a seguinte:
Obs: Se você quiser continuar a partir deste artigo faça o download do projeto UniversidadeMacoratti_2.zip para abri-lo no Visual Web Developer 2010 Express Edition.
Se executarmos a aplicação e clicarmos na aba Estudantes iremos obter a página a seguir a partir da qual poderemos acionar as funcionalidades para ordenação, filtragem e paginação;
Incluindo links para ordenação nas colunas da página Index dos Estudantes
Para incluir links para ordenação nas colunas do cabeçalho da página Index vamos alterar o método Index do Controller Estudante e incluir o código necessário na view Index;
1- Incluindo a funcionalidade de ordenação no método Index;
Abra o arquivo EstudanteController.vb que esta na pasta Controller (Controller/EstudanteController.vb) e substitua o método Index abaixo:
' GET: /Estudante/ Function Index() As ViewResult Return View(db.Estudantes.ToList()) End Function |
Pelo seguinte código:
' ' GET: /Student/ Public Function Index(ordenacaoOrdem As String) ViewBag.NomeOrdenacaoParm = IIf(String.IsNullOrEmpty(ordenacaoOrdem), "Nome desc", "") ViewBag.DataOrdenacaoParm = IIf(ordenacaoOrdem = "Data", "Data desc", "Data") Dim estudantes = From est In db.Estudantes Select est Select Case ordenacaoOrdem Case "Nome desc" estudantes = estudantes.OrderByDescending(Function(est) est.SobreNome) Exit Select Case "Data" estudantes = estudantes.OrderBy(Function(est) est.DataMatricula) Exit Select Case "Data desc" estudantes = estudantes.OrderByDescending(Function(est) est.DataMatricula) Exit Select Case Else estudantes = estudantes.OrderBy(Function(est) est.SobreNome) Exit Select End Select Return View(estudantes.ToList()) End Function |
Este código recebe um parâmetro ordenacaoOrdem a partir de uma Query String na URL, a qual é fornecida pela ASP .NET MVC como um parâmetro para o método action. O parâmetro será uma string que pode ser "Nome" ou "Data", opcionalmente seguida por um espaço e a string "desc" para especificar a ordenação decrescente.
A primeira vez que a página é requisitada, não haverá query string e os estudantes serão exibidos na ordem ascendente de sobrenome.
Quando o usuário clicar em um link da coluna para realizar a ordenação, o respectivo valor ordenacaoOrdem será fornecido para a query string.
As variáveis ViewBag são usadas de forma que a view pode configurar os hiperlinks das colunas de ordenação com os valores apropriados da query string.
Obs: ViewBag é usada para passar dados dos controllers para as views da mesma forma que ViewData. (ViewBag é um tipo dinâmico)
ViewBag.NomeOrdenacaoParm = IIf(String.IsNullOrEmpty(ordenacaoOrdem), "Nome desc", "") ViewBag.DataOrdenacaoParm = IIf(ordenacaoOrdem = "Data", "Data desc", "Data")
O primeiro código define que se o parâmetro ordenacaoOrdem for null ou vazio (empty) a variável ViewBag.NomeOrdenacaoParm deverá ser definida para "Nome desc", caso contrário deverá ser definido para uma string vazia ("").
Existem 4 possibilidades dependendo como os dados estão atualmente ordenados:
O método utiliza o LINQ to Entities para especificar a coluna a ser ordenada. O código cria uma variável IQueryable antes da instrução Select Case, modifica-a na instrução Select Case e chama o método ToList depois da instrução Select Case.
Quando você cria e modifica variáveis IQueryable, nenhuma consulta é enviada para o banco de dados. A consulta não é executada até que você converta o objeto IQueryable em uma coleção chamando o método ToList. Por isso, este código resulta em uma única consulta que não é executada até a chamada da instrução return view.
Incluindo hiperlinks no cabeçalho das colunas da View Index para Estudantes
Na pasta Views\Estudante abra o arquivo Index.vbhtml e substitua os elementos <tr> e <th> para o cabeçalho da linha pelo seguinte código:
<tr>
<th>
SobreNome </th> <th>Nome </th> <th>Data da Matricula </th> </tr>
|
<tr>
<th>
@Html.ActionLink( "Sobrenome", "Index", New With {.ordenacaoOrdem = ViewBag.NomeOrdenacaoParm, .currentFilter = ViewBag.CurrentFilter})</th> <th>Nome </th> <th>@Html.ActionLink( "Data Matrícula", "Index", New With {.ordenacaoOrdem = ViewBag.DataOrdenacaoParm, .currentFilter = ViewBag.CurrentFilter})</th> </tr>
|
Este código utiliza a informação da propriedade ViewBag para definir os hiperlinks com os valores das strings para a consulta.
Executando o projeto e clicando na aba Estudantes temos o seguinte resultado:
Para testar a funcionalidade basta clicar nos links Sobrenome e Data Matricula.
Incluindo uma caixa de Procura para estudantes na página Index
Para incluir a funcionalidade que permite filtrar dados dos estudantes vamos incluir um controle TextBox e um controle Button na view e fazer os ajustes correspondentes no método Index. A caixa de texto (TextBox) vai permitir que o usuário informe uma string para busca no nome e sobrenome do estudante.
Abra o arquivo EstudanteController.vb na pasta Controllers e vamos alterar o método Index para ter o seguinte código:
' GET: /Student/ Public Function Index(ordenacaoOrdem As String, strCriterio As String) ViewBag.NomeOrdenacaoParm = IIf(String.IsNullOrEmpty(ordenacaoOrdem), "Nome desc", "") ViewBag.DataOrdenacaoParm = IIf(ordenacaoOrdem = "Data", "Data desc", "Data") Dim estudantes = From est In db.Estudantes Select est If Not String.IsNullOrEmpty(strCriterio) Then estudantes = estudantes. Where(Function(est) est.SobreNome.ToUpper().Contains(strCriterio.ToUpper()) _ OrElse est.Nome.ToUpper().Contains(strCriterio.ToUpper())) End If Select Case ordenacaoOrdem Case "Nome desc" estudantes = estudantes.OrderByDescending(Function(est) est.SobreNome) Exit Select Case "Data" estudantes = estudantes.OrderBy(Function(est) est.DataMatricula) Exit Select Case "Data desc" estudantes = estudantes.OrderByDescending(Function(est) est.DataMatricula) Exit Select Case Else estudantes = estudantes.OrderBy(Function(est) est.SobreNome) Exit Select End Select Return View(estudantes.ToList()) End Function |
Fizemos as seguintes alterações no método Index: (as inclusões estão destacadas na cor azul)
1- Incluímos o parâmetro strCriterio do tipo string no método Index;
2- Incluímos uma cláusula Where na instrução LINQ que seleciona somente
estudantes cujo nome ou sobrenome contenham a string de critério informada na
caixa de texto que iremos incluir na view;
Para incluir a caixa de texto na View abra o arquivo Index.vbhtml na pasta Views\Estudantes e inclua um título, um TextBox e um Button antes a tag table conforme mostra o texto destacado no trecho de código da página Index.vbhtml abaixo:
@ModelType IEnumerable(Of UniversidadeMacoratti.UniversidadeMacoratti.Models.Estudante)@Code ViewData( "Title") = "Estudantes"End Code < h2>Estudantes</h2>< p>@Html.ActionLink( "Criar Novo", "Criar")</ p>
@ <p>Procurar por nome: @Html.TextBox( "strCriterio", ViewBag.CurrentFilter) <input type="submit" value="Procurar" /></p> End Using< table>..... .....
|
Execute o projeto e informe um texto como critério de busca na caixa de texto e clique no botão Procurar para verificar o resultado:
Implementando a funcionalidade de paginação
Vamos agora implementar a paginação e para isso vamos usar o componente PagedList.
Para obter o componente você pode usar o NuGet ou o próprio ambiente do Visual Web Developer ou Visual Studio via menu Tools -> Extension Manager e pesquisar pelo componente para fazer o seu download:
Se você não conseguir usando este caminho, procure no Google por PagedList e faça o download no link : http://pagedlist.codeplex.com/releases/view/31087
Apos o download clique no menu Project -> Add Reference, e, a seguir clique em Browse e selecione o local onde você instalou o componente, selecione PagedList.dll e clique em OK;
Após referenciar o componente abra o arquivo EstudanteController.vb na pasta Controllers e inclua a instrução imports para o PagedList;
Imports
PagedListA seguir vamos alterar o método Index deste arquivo conforme o código abaixo:
' GET: /Student/ Public Function Index(ordenacaoOrdem As String, filtroAtual As String, strCriterio As String, pagina As System.Nullable(Of Integer)) ViewBag.CurrentOrder = ordenacaoOrdem ViewBag.NomeOrdenacaoParm = IIf(String.IsNullOrEmpty(ordenacaoOrdem), "Nome desc", "") ViewBag.DataOrdenacaoParm = IIf(ordenacaoOrdem = "Data", "Data desc", "Data") If Request.HttpMethod = "GET" Then strCriterio = filtroAtual Else pagina = 1 ViewBag.CurrentFilter = strCriterio Dim estudantes = From est In db.Estudantes Select est If Not String.IsNullOrEmpty(strCriterio) Then estudantes = estudantes. Where(Function(est) est.SobreNome.ToUpper().Contains(strCriterio.ToUpper()) _ OrElse est.Nome.ToUpper().Contains(strCriterio.ToUpper())) End If Select Case ordenacaoOrdem Case "Nome desc" estudantes = estudantes.OrderByDescending(Function(est) est.SobreNome) Exit Select Case "Data" estudantes = estudantes.OrderBy(Function(est) est.DataMatricula) Exit Select Case "Data desc" estudantes = estudantes.OrderByDescending(Function(est) est.DataMatricula) Exit Select Case Else estudantes = estudantes.OrderBy(Function(est) est.SobreNome) Exit Select End Select Dim paginaTamanho As Integer = 3 Dim paginaNumero As Integer = (If(pagina, 1)) Return View(estudantes.ToPagedList(paginaNumero, paginaTamanho)) End Function |
Este código inclui os seguintes parâmetros ao método Index:
Na primeira execução da página ou se o usuário clicar não clicar no link de paginação, a variável pagina será null. Se o link de paginação for clicado a variável irá conter o número da página a ser exibida.
A propriedade ViewBag fornece a view com a ordenação atual, pois isto deve ser incluído nos links de paginação a fim de manter mesma ordenação da paginação:
ViewBag.CurrentOrder = ordenacaoOrdem
A outra propriedade ViewBag fornece a view com a string do filtro atual, pois esta string deve ser armazenada no TextBox quando a página for exibida. Além disso a string deve ser incluída nos links de paginação afim de manter as configurações de filtro durante a paginação.
Se a string de busca for alterada durante a paginação, a página tem que ser resetada para o valor 1, pois um novo filtro pode resultar em dados diferentes na exibição:
If Request.HttpMethod
= "GET" Then
strCriterio = filtroAtual
Else pagina =
1
ViewBag.CurrentFilter
= strCriterio
No final a consulta é convertida para um PagedList ao invés de ToList de forma que ele será passado para view em uma coleção que suporta a paginação:
Dim paginaTamanho As Integer = 3
Dim
paginaIndice As Integer = (If(pagina, 1)) -1
Return View(estudantes.ToPagedList(paginaIndice
, paginaTamanho))
O método ToPageList() usa o índice da página, o qual é base zero, ao invés do número da página que é base 1. Por isso estamos subtraindo uma unidade.
Vamos agora definir os links de paginação na View Index do Estudante.
Abra o arquivo Index.vbhtml na pasta Views\Estudante\ e altere o código conforme abaixo:
@ModelType PagedList.IPagedList(Of UniversidadeMacoratti.UniversidadeMacoratti.Models.Estudante) @Code ViewData("Title") = "Estudantes" End Code <h2>Estudantes</h2> <p> @Html.ActionLink("Criar Novo", "Criar") </p> @Using Html.BeginForm() @<p> Procurar por nome: @Html.TextBox("strCriterio", ViewBag.CurrentFilter) <input type="submit" value="Procurar" /></p> End Using <table> <tr> <th> @Html.ActionLink("Sobrenome", "Index", New With {.ordenacaoOrdem = ViewBag.NomeOrdenacaoParm, .currentFilter = ViewBag.CurrentFilter}) </th> <th> Nome </th> <th> @Html.ActionLink("Data Matrícula", "Index", New With {.ordenacaoOrdem = ViewBag.DataOrdenacaoParm, .currentFilter = ViewBag.CurrentFilter}) </th> </tr> @For Each item In Model Dim currentItem = item @<tr> <td> @Html.DisplayFor(Function(modelItem) currentItem.SobreNome) </td> <td> @Html.DisplayFor(Function(modelItem) currentItem.Nome) </td> <td> @Html.DisplayFor(Function(modelItem) currentItem.DataMatricula) </td> <td> @Html.ActionLink("Editar", "Edit", New With {.id = currentItem.EstudanteID}) | @Html.ActionLink("Detalhes", "Details", New With {.id = currentItem.EstudanteID}) | @Html.ActionLink("Deletar", "Delete", New With {.id = currentItem.EstudanteID}) </td> </tr> Next </table> <div> Página @(IIf(Model.PageCount < Model.PageNumber, 0, Model.PageNumber)) de @Model.PageCount @If Model.HasPreviousPage Then @Html.ActionLink("<<", "Index", New With {.pagina = 1, .ordenacaoOrdem = ViewBag.CurrentSort, .currentFilter = ViewBag.CurrentFilter}) @Html.Raw(" ") @Html.ActionLink("< Anterior", "Index", New With {.pagina = Model.PageNumber - 1, .ordenacaoOrdem = ViewBag.CurrentSort, .currentFilter = ViewBag.CurrentFilter}) Else @:<< @Html.Raw(" ") @:< Anterior End If @If Model.HasNextPage Then @Html.ActionLink("Próxima >", "Index", New With {.pagina = Model.PageNumber + 1, .ordenacaoOrdem = ViewBag.CurrentSort, .currentFilter = ViewBag.CurrentFilter}) @Html.Raw(" ") @Html.ActionLink(">>", "Index", New With {.pagina = Model.PageCount, .ordenacaoOrdem = ViewBag.CurrentSort, .currentFilter = ViewBag.CurrentFilter}) Else @:Próxima > @Html.Raw(" ") @:>> End If </div> |
O código que foi alterado esta destacado em azul.
@ModelType PagedList.IPagedList(Of UniversidadeMacoratti.UniversidadeMacoratti.Models.Estudante)
No início da página substituímos a declaração ModelType onde ao invés da view usar o objeto List agora estamos usando o objeto PagedList.
No final da página temos a definição do código que controla a paginação.
<div>
Página @(IIf(Model.PageCount < Model.PageNumber, 0, Model.PageNumber))
de @Model.PageCount
@If Model.HasPreviousPage Then
@Html.ActionLink("<<", "Index", New
With {.pagina = 1, .ordenacaoOrdem = ViewBag.CurrentSort, .currentFilter =
ViewBag.CurrentFilter})
@Html.Raw(" ")
@Html.ActionLink("< Anterior", "Index",
New With {.pagina = Model.PageNumber - 1, .ordenacaoOrdem = ViewBag.CurrentSort,
.currentFilter = ViewBag.CurrentFilter})
Else
@:<<
@Html.Raw(" ")
@:< Anterior
End If
@If Model.HasNextPage Then
@Html.ActionLink("Próxima >", "Index",
New With {.pagina = Model.PageNumber + 1, .ordenacaoOrdem = ViewBag.CurrentSort,
.currentFilter = ViewBag.CurrentFilter})
@Html.Raw(" ")
@Html.ActionLink(">>", "Index", New
With {.pagina = Model.PageCount, .ordenacaoOrdem = ViewBag.CurrentSort, .currentFilter
= ViewBag.CurrentFilter})
Else
@:Próxima >
@Html.Raw(" ")
@:>>
End If
</div>
Executando o projeto iremos obter:
Na base da página temos que:
Dessa forma concluímos todos os ajustes nos controllers e views para implementarmos as funcionalidades de ordenação, filtragem e paginação de dados.
Acompanhe a continuação neste link: ASP .NET MVC 3 - Alterando o modelo de dados - Data Annotations - EF - IV
Pegue o projeto completo aqui: UniversidadeMacoratti_3.zip
"E a ninguém na terra chameis vosso pai,
porque um só é o vosso Pai, o qual esta nos céus."
"Nem vos chameis mestres, porque um só é o vosso Mestre, que é o Cristo." Mateus
23:9-10
Referências: