ASP .NET Core - Criando uma aplicação ASP .NET Core MVC com o VS 2017 - VII

 Neste artigo eu vou mostrar como criar uma aplicação ASP .NET Core MVC usando o VS 2017.

Continuando a sexta parte do artigo vamos implementar a funcionalidade de procurar informações em nossa aplicação.

Para isso vamos implementar a funcionalidade de buscar dados no método Action Index e procurar filmes por titulo e por gênero.

Filtrando os filmes pelo título

Abra o controlador FilmesController na pasta Controllers e altere o método Index() conforme abaixo:

        // GET: Filmes
        public async Task<IActionResult> Index(string criterioBusca)
        {
            var filmes = from m in _context.Filme
                               select m;
            if (!String.IsNullOrEmpty(criterioBusca))
            {
                filmes = filmes.Where(f => f.Titulo.Contains(criterioBusca));
            }
            return View(await filmes.ToListAsync());
        }

Na primeira linha do método temos uma consulta LINQ para selecionar filmes :

   var filmes = from m in _context.Filme
                       select m;

Aqui a consulta foi apenas definida e não executada ainda.

Na sequência verificamos se o parâmetro criterioBusca não for vazio nem nulo a consulta de filmes será modificada para filtrar pelo critério informado o titulo dos filmes.

  if (!String.IsNullOrEmpty(searchString))
  {
     filmes = filmes.Where(s => s.Titulo.Contains(searchString));
  }

O código s => s.Titulo.Contains() é uma Expressão Lambda. As lambdas são usadas em consultas LINQ baseadas em método como argumentos para métodos de operador de consulta padrão, como o método Where ou Contains (usado no código acima).

As consultas LINQ não são executadas quando são definidas ou quando são modificadas chamando um método, como Where, Contains ou OrderBy. Em vez disso, a execução da consulta é diferida. Isso significa que a avaliação de uma expressão é atrasada até que seu valor realizado seja iterado ou o método ToListAsync seja chamado.

Nota: O método Contains é executado no banco de dados, não no código C# mostrado acima. A sensibilidade de maiúsculas e minúsculas na consulta depende do banco de dados e do collation. No SQL Server, o método Contains mapeia para a instrução SQL LIKE, que é insensível a maiúsculas e minúsculas. No SQLlite, com o collation padrão, ele é sensível a maiúsculas e minúsculas.

Agora, com a aplicação em execução, abra o navegador e navegue para /Filmes/Index :

A seguir anexe a seguinte string de consulta (criterioBusca) na URL:  ?criterioBusca=ilha e tecle Enter:

Agora vamos alterar a assinatura do método Index do controlador para usar um parâmetro chamado id ao invês de criterioBusca.

Fazendo isso o parâmetro id irá corresponder ao marcador de possível opcional  {id} usado para as rotas padrão que foram definidas no arquivo Startup.cs :

      ....
     app.UseMvc(routes =>
      {
                routes.MapRoute(
                    name: "default",
                    template: "{controller=Home}/{action=Index}/{id?}");
    });
   ....

Então a seguir vamos alterar o método Index do controlador para usar id ao invês de criterioBusca:

        // GET: Filmes
        public async Task<IActionResult> Index(string id)
        {
            var filmes = from m in _context.Filme
                               select m;
            if (!String.IsNullOrEmpty(id))
            {
                filmes = filmes.Where(f => f.Titulo.Contains(id));
            }
            return View(await filmes.ToListAsync());
        }

Fazendo assim agora podemos passar o valor de busca como um dado de rota (o segmento da URL) ao invês de um valor string de consulta.

Podemos agora navegar para :  /Filmes/Index/ilha     (onde ilha é o critério de busca que esta sendo passado como uma informação de rota)

Fica muito mais elegante mas não seria viável ficar passando as informações modificando a URL, então vamos adicionar na view Index.cshtml uma caixa de busca para nos ajudar a filtrar os filmes pelo critério.

Antes temos que retornar o método Index do controlador ao seu código original :

        // GET: Filmes
        public async Task<IActionResult> Index(string criterioBusca)
        {
            var filmes = from m in _context.Filme
                               select m;
            if (!String.IsNullOrEmpty(criterioBusca))
            {
                filmes = filmes.Where(f => f.Titulo.Contains(criterioBusca));
            }
            return View(await filmes.ToListAsync());
        }

Agora abra a view Index.cshtml na pasta /Views/Filme e vamos alterar o seu código incluindo as linhas de código destacadas em azul abaixo :

@model IEnumerable<MvcFilme.Models.Filme>
@{
    ViewData["Title"] = "Index";
}
<h2>Filmes</h2>
<p>
    <a asp-action="Create">Criar Novo</a>
</p>
<form asp-controller="Filmes" asp-action="Index">
    <p>
        Title: <input type="text" name="criterioBusca">
        <input type="submit" value="Filtrar" />
    </p>
</form>
...

A tag HTMl <form> usa a tag Helper Form de  maneira que quando o formulário for submetido (Enviado) a string criterioBusca será postada para a Action Index no controlador Filmes realizando o filtro:

Filtrando os filmes pelo Gênero

Para incluir a funcionalidade de filtrar pelos gêneros dos filmes teremos que criar uma View Model representada pela classe chamada FilmeGeneroViewModel na pasta Models.

Nota:  Se você não conhece o padrão View Model leia este artigo: NET - O padrão MVVM (Model-View-ViewModel) revisitado - Macoratti

Clique com o botão direito do mouse sobre a pasta Models e a seguir clique em Add -> Class e informe o nome FilmeGeneroViewModel;

A seguir inclua o código abaixo nesta classe:

using Microsoft.AspNetCore.Mvc.Rendering;
using System.Collections.Generic;
namespace MvcFilme.Models
{
    public class FilmeGeneroViewModel
    {
        public List<Filme> filmes;
        public SelectList generos;
        public string filmeGenero { get; set; }
    }
}

A nossa View Model contém:

Essa classe será usada como nosso Model para retornar a lista de filmes e lista de gêneros para exibição na view Index.

Agora vamos alterar o método Index do controlador FilmesController conforme o código a seguir:

       // GET: Filmes
        public async Task<IActionResult> Index(string filmeGenero,string criterioBusca)
        {
            IQueryable<string> consultaGenero = from m in _context.Filme
                                                                    orderby m.Genero
                                                                    select m.Genero;
            var filmes = from m in _context.Filme
                               select m;
            if (!String.IsNullOrEmpty(criterioBusca))
            {
                filmes = filmes.Where(s => s.Titulo.Contains(criterioBusca));
            }
            if (!String.IsNullOrEmpty(filmeGenero))
            {
                filmes = filmes.Where(x => x.Genero == filmeGenero);
            }
            var filmeGeneroVM = new FilmeGeneroViewModel();
            filmeGeneroVM.generos = new SelectList(await consultaGenero.Distinct().ToListAsync());
            filmeGeneroVM.filmes = await filmes.ToListAsync();
            return View(filmeGeneroVM);
        }

Nosso método Index passou a receber dois parâmetros : filmeGenero e criterioBusca.

No código estamos usando uma  consulta LINQ para retornar todos os gêneros dos filmes:

            IQueryable<string> consultaGenero = from m in _context.Filme
                                                                         orderby m.Genero
                                                                         select m.Genero;

Depois verificamos se o parâmetro filmeGenero não é vazio nem nulo, e neste caso, a consulta de generos será modificada para filtrar pelo critério informado no gênero dos filmes.

            if (!String.IsNullOrEmpty(filmeGenero))
            {
                filmes = filmes.Where(x => x.Genero == filmeGenero);
            }

A seguir criamos uma instância da classe FilmeGeneroViewModel() e usamos a classe SelectList para projetar uma lista de gêneros distintas para não haver gêneros duplicados.

Agora vamos exibir a lista de gêneros na página Index de forma que o usuário possa escolher por qual gênero deseja filtrar.

Abra o arquivo Index.cshtml e altere o código conforme mostrado a seguir:

@model MvcFilme.Models.FilmeGeneroViewModel
@{
    ViewData["Title"] = "Index";
}
<h2>Filmes</h2>
<p>
    <a asp-action="Create">Criar Novo</a>
</p>
<form asp-controller="Filmes" asp-action="Index">
    <p>
        <select asp-for="filmeGenero" asp-items="Model.generos">
            <option value="">Todos</option>
        </select>
        Titulo: <input type="text" name="criterioBusca">
        <input type="submit" value="Filtrar" />
    </p>
</form>
<table class="table">
    <thead>
        <tr>
                <th>
                    @Html.DisplayNameFor(model => model.filmes[0].Titulo)
                </th>
                <th>
                    @Html.DisplayNameFor(model => model.filmes[0].Lancamento)
                </th>
                <th>
                    @Html.DisplayNameFor(model => model.filmes[0].Genero)
                </th>
                <th>
                    @Html.DisplayNameFor(model => model.filmes[0].Preco)
                </th>
            <th></th>
        </tr>
    </thead>
    <tbody>
@foreach (var item in Model.filmes) {
        <tr>
            <td>
                @Html.DisplayFor(modelItem => item.Titulo)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.Lancamento)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.Genero)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.Preco)
            </td>
            <td>
                <a asp-action="Edit" asp-route-id="@item.ID">Editar</a> |
                <a asp-action="Details" asp-route-id="@item.ID">Detalhes</a> |
                <a asp-action="Delete" asp-route-id="@item.ID">Deletar</a>
            </td>
        </tr>
}
    </tbody>
</table>

Observe que agora o modelo usado é a classe FilmeGeneroViewModel : @model MvcFilme.Models.FilmeGeneroViewModel

Incluimos um dropdownlist para exibir todos os gêneros dos filmes na página :

 <select asp-for="filmeGenero" asp-items="Model.generos">
            <option value="">Todos</option>
 </select>

Agora execute a aplicação novamente e abra na página de filmes para visualizar as alterações que permitem filtrar por gênero e por título do filme:

Na próxima parte do artigo vamos mostrar como podemos tratar com a alteração do modelo de dados com inclusão de novos campos.

Pegue o projeto funcionando até aqui neste link:  MvcFilme7.zip

Mas a hora vem, e agora é, em que os verdadeiros adoradores adorarão o Pai em espírito e em verdade; porque o Pai procura a tais que assim o adorem.
Deus é Espírito, e importa que os que o adoram o adorem em espírito e em verdade.

João 4:23,24

Veja os Destaques e novidades do SUPER DVD Visual Basic (sempre atualizado) : clique e confira !

Quer migrar para o VB .NET ?

Quer aprender C# ??

Quer aprender os conceitos da Programação Orientada a objetos ?

Quer aprender o gerar relatórios com o ReportViewer no VS 2013 ?

  Gostou ?   Compartilhe no Facebook   Compartilhe no Twitter

Referências:


José Carlos Macoratti