Neste artigo, vamos iniciar a criação de uma aplicação ASP .NET Core MVC usando o Entity Framework Core no Visual Studio 2017.
Estamos criando uma aplicação Web usando ASP.NET Core 1.1 MVC com Entity Framework Core 1.1 e Visual Studio 2017.
No artigo anterior, implementamos o filtro de dados adicionando uma caixa de pesquisa na página Index.
Continuaremos incrementando a página Index incluindo o recurso da paginação dos dados.
1 – Incluindo a paginação na página Index
Para adicionar o recurso da paginação para a página Index dos estudantes, vamos criar uma classe chamada PaginatedList que usa as instruções Skip e Take para filtrar dados no servidor em vez de sempre recuperar todas as linhas da tabela.
Em seguida, faremos alterações adicionais no método Index do controlador e depois vamos adicionar botões de paginação na respectiva view Index.
Selecione o projeto, no menu Tools clique em Add Class, informe o nome PaginatedList.cs e clique no botão Add.
A seguir, inclua o código abaixo nesta classe:
using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Microsoft.EntityFrameworkCore; namespace UniversidadeMacoratti { public class PaginatedList<T> : List<T> { public int PageIndex { get; private set; } public int TotalPages { get; private set; } public PaginatedList(List<T> items, int count, int pageIndex, int pageSize) { PageIndex = pageIndex; TotalPages = (int)Math.Ceiling(count / (double)pageSize); this.AddRange(items); } public bool HasPreviousPage { get { return (PageIndex > 1); } } public bool HasNextPage { get { return (PageIndex < TotalPages); } } public static async Task<PaginatedList<T>> CreateAsync(IQueryable<T> source, int pageIndex, int pageSize) { var count = await source.CountAsync(); var items = await source.Skip((pageIndex - 1) * pageSize).Take(pageSize).ToListAsync(); return new PaginatedList<T>(items, count, pageIndex, pageSize); } } }
O método CreateAsync neste código obtém o tamanho da página, número de página e aplica as instruções Skip e Take ao IQueryable. Quando ToListAsync for chamado no IQueryable, ele retornará uma lista contendo apenas a página solicitada. As propriedades HasPreviousPage e HasNextPage podem ser usadas para ativar ou desativar os botões de paginação Anterior e Próxima.
O método CreateAsync é usado em vez de um construtor para criar o objeto PaginatedList<T> porque construtores não podem executar código assíncrono.
2 – Incluindo o recurso da paginação no método Index do Controlador
Agora vamos incluir o recurso de paginação no controlador EstudantesController.
Abra o arquivo EstudantesController.cs e altere o método Index() conforme o código mostrado a seguir:
// GET: Estudantes public async Task<IActionResult> Index( string ordem, string filtroAtual, string filtro, int? pagina) { ViewData["ordemAtual"] = ordem; ViewData["NomeParm"] = String.IsNullOrEmpty(ordem) ? "nome_desc" : ""; ViewData["DataParm"] = ordem == "Data" ? "data_desc" : "Data"; if (filtro != null) { pagina = 1; } else { filtro = filtroAtual; } ViewData["filtroAtual"] = filtro; var estudantes = from est in _context.Estudantes select est; if (!String.IsNullOrEmpty(filtro)) { estudantes = estudantes.Where(est => est.SobreNome.Contains(filtro) || est.Nome.Contains(filtro)); } switch (ordem) { case "nome_desc": estudantes = estudantes.OrderByDescending(est => est.SobreNome); break; case "Data": estudantes = estudantes.OrderBy(est => est.DataMatricula); break; case "data_desc": estudantes = estudantes.OrderByDescending(est => est.DataMatricula); break; default: estudantes = estudantes.OrderBy(est => est.SobreNome); break; } int pageSize = 3; return View(await PaginatedList<Estudante>.CreateAsync(estudantes.AsNoTracking(), pagina ?? 1, pageSize)); }
Esse código adiciona um parâmetro de número de página, um parâmetro de ordem de classificação atual e um parâmetro de filtro atual para a assinatura do método.
Na primeira vez que a página for exibida, ou se o usuário não clicar em um link de paginação ou classificação, todos os parâmetros serão nulos. Se um link de paginação for clicado, a variável pagina conterá o número da página a ser exibido.
O elemento ViewData chamado ordemAtual fornece a view com a ordem de classificação atual, pois isso deve ser incluído nos links de paginação para manter a ordem de classificação durante a paginação.
O elemento ViewData denominado filtroAtual, fornece a view com a string de filtro actual. Esse valor deve ser incluído nos links de paginação para manter as configurações de filtro durante a paginação, e deve ser restaurado para a caixa de texto quando a página é exibida novamente.
Se a seqüência de pesquisa for alterada durante a paginação, a página deve ser redefinida para 1, pois o novo filtro pode resultar em dados diferentes para exibição. A string de pesquisa é alterada quando um valor é inserido na caixa de texto e o botão Enviar é pressionado. Nesse caso, o parâmetro filtro não é nulo.
Ao final do método Index, o método PaginatedList.CreateAsync converte a consulta do estudante em uma única página de estudantes, em um tipo de coleção que ofereça suporte à paginação. Essa única página de alunos é então passada para a view.
O método PaginatedList.CreateAsync toma um número de página. Os dois pontos de interrogação representam o operador nulo-coalescente. O operador nulo-coalescente define um valor padrão para um tipo anulável; A expressão “página ?? 1” significa retornar o valor da página se ela tiver um valor, ou retornar 1 se a página for nula.
3 – Incluindo os links na view Index
Agora vamos definir o código abaixo na view Index da pasta Views/Estudantes:
@model PaginatedList<UniversidadeMacoratti.Models.Estudante> @{ ViewData["Title"] = "Index"; } <h2>Estudantes</h2> <p> <a asp-action="Create">Criar Novo Estudante</a> </p> <form asp-action="Index" method="get"> <div class="form-actions no-color"> <p> Procurar por nome : <input type="text" name="filtro" value="@ViewData["filtroAtual"]" /> <input type="submit" value="Procurar" class="btn btn-default" /> | <a asp-action="Index">Retornar para lista</a> </p> </div> </form> <table class="table"> <thead> <tr> <th> <a asp-action="Index" asp-route-ordem="@ViewData["NomeParam"]" asp-route-filtroAtual="@ViewData["filtroAtual"]">Sobrenome</a> </th> <th> Nome </th> <th> <a asp-action="Index" asp-route-ordem="@ViewData["DataParm"]" asp-route-filtroAtual="@ViewData["filtroAtual"]">Data de Matrícula</a> </th> <th></th> </tr> </thead> <tbody> @foreach (var item in Model) { <tr> <td> @Html.DisplayFor(modelItem => item.SobreNome) </td> <td> @Html.DisplayFor(modelItem => item.Nome) </td> <td> @Html.DisplayFor(modelItem => item.DataMatricula) </td> <td> <a asp-action="Edit" asp-route-id="@item.EstudanteID">Editar</a> | <a asp-action="Details" asp-route-id="@item.EstudanteID">Detalhes</a> | <a asp-action="Delete" asp-route-id="@item.EstudanteID">Deletar</a> </td> </tr> } </tbody> </table> @{ var prevDisabled = !Model.HasPreviousPage ? "disabled" : ""; var nextDisabled = !Model.HasNextPage ? "disabled" : ""; } <a asp-action="Index" asp-route-ordem="@ViewData["ordemAtual"]" asp-route-pagina="@(Model.PageIndex - 1)" asp-route-filtroAtual="@ViewData["filtroAtual"]" class="btn btn-default @prevDisabled"> Anterior </a> <a asp-action="Index" asp-route-ordem="@ViewData["ordemAtual"]" asp-route-pagina="@(Model.PageIndex + 1)" asp-route-filtroAtual="@ViewData["filtroAtual"]" class="btn btn-default @nextDisabled"> Próximo </a>
Nota: Novamente estamos usando as Tag Helpers: <form> , asp-action e asp-route.
Os links de cabeçalho de coluna usam a string de consulta para passar a string de pesquisa atual para o controlador, para que o usuário possa classificar os resultados do filtro:
<a asp-action="Index" asp-route-ordem="@ViewData["DataParm"]" asp-route-filtroAtual="@ViewData["filtroAtual"]">Data de Matrícula</a>
Os botões de paginação são exibidos usando tag-helpers:
<a asp-action="Index" asp-route-ordem="@ViewData["ordemAtual"]" asp-route-pagina="@(Model.PageIndex - 1)" asp-route-filtroAtual="@ViewData["filtroAtual"]" class="btn btn-default @prevDisabled"> Anterior </a> <a asp-action="Index" asp-route-ordem="@ViewData["ordemAtual"]" asp-route-pagina="@(Model.PageIndex + 1)" asp-route-filtroAtual="@ViewData["filtroAtual"]" class="btn btn-default @nextDisabled"> Próximo </a>
Execute o projeto e abra a página dos estudantes:
Clique nos links de paginação em ordens de classificação diferentes para garantir que a paginação esta funcionando. Em seguida, digite uma string de caracteres de pesquisa e tente a paginação novamente para verificar se a paginação também funciona corretamente com classificação e filtragem.
Na próxima parte do artigo, criaremos uma página para exibir estatísticas sobre os estudantes.
Pegue o projeto funcionando aqui: UniversidadeMacoratti.zip