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:
- Visual Studio 2010 SP1 ou Visual Web Developer Express 2010 SP1 (ao instalar usando este link os demais itens serão instalados automaticamente)
- ASP.NET MVC 3 Tools Update
- Microsoft SQL Server Compact 4.0
- Microsoft Visual Studio 2010 SP1 Tools for SQL Server Compact 4.0
Esta é terceira parte do artigo e se você esta chegando agora, deve ler obrigatoriamente as partes anteriores, que você pode acessar por esses links: primeira e segunda.
Neste artigo, vamos abordar e 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 está 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
Esse 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 é só 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 quatro possibilidades, dependendo de como os dados estão atualmente ordenados:
- Se a ordem atual for Sobrenome ascendente, o link Sobrenome deve especificar Sobrenome descendente, e o link Data de Matrícula deve especificar Data ascendente;
- Se a ordem atual for Sobrenome descendente, os links devem indicar Sobrenome ascendente e Data ascendente;
- Se a ordem atual for Data ascendente, os links devem indicar Sobrenome ascendente e Data descendente;
- Se a ordem atual for Data descendente, os links devem indicar Sobrenome ascendente e Data ascendente;
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, esse 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>
Esse 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, que está 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 em negrito):
- Incluímos o parâmetro strCriterio do tipo string no método Index;
- 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 da 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>
@Using Html.BeginForm()
@<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
Agora, vamos implementar a paginação. E para isso, usaremos o componente PagedList.
Para obter o componente, você pode usar o NuGet, o próprio ambiente do Visual Web Developer ou do Visual Studio via menu Tools -> Extension Manager e pesquisar pelo componente para fazer o seu download:
Se, mesmo seguindo esse caminho, você não conseguir, procure no Google por PagedList e faça o download neste link. 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 PagedList
A 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
Esse código inclui os seguintes parâmetros ao método Index:
- Página
- Filtro Atual
Na primeira execução da página, ou se o usuário não clicar no link de paginação, a variável “página” 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 isso 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 essa 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 a fim 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, em vez de ToList, de forma que ele será passado para a 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 0, em vez 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 está destacado em negrito.
@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:
- O símbolo << indica que iremos para página inicial;
- O símbolo >> indica que iremos para a última página;
- O símbolo < Anterior vai para página anterior;
- O símbolo Próxima > vai para próxima página.
Dessa forma, concluímos todos os ajustes nos controllers e views para implementarmos as funcionalidades de ordenação, filtragem e paginação de dados.
Pegue o projeto completo aqui: UniversidadeMacoratti_3.zip