.NET

8 nov, 2017

ASP .NET Core – Iniciando com ASP .NET Core MVC e Entity Framework Core no VS 2017 – Parte 07

Publicidade

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