ASP.NET Core - Exibindo e atualizando dados relacionados- III


Neste tutorial veremos como exibir e atualizar dados relacionados em uma aplicação ASP .NET Core MVC.

Vamos continuar a segunda parte do artigo criando os controladores e as views em nosso projeto.

Criando os controladores para Clientes e Pedidos

Na pasta Controllers vamos criar o controlador ClientesController :

using Aspn_MasterDetail.Repositories;
using Aspn_MasterDetail.ViewModels;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
namespace Aspn_MasterDetail.Controllers
{
    public class ClientesController : Controller
    {
        private readonly ClientesRepository clienteRepo;
        public ClientesController(ClientesRepository repo)
        {
            clienteRepo = repo;
        }
        public IActionResult Index()
        {
            var listaClientes = clienteRepo.GetClientes();
            return View(listaClientes);
        }
        public ActionResult Create()
        {
            var cliente = clienteRepo.CriaCliente();
            return View(cliente);
        }       
        [HttpPost]
        public ActionResult Create([Bind("ClienteId,Nome, Email")] ClienteEditaViewModel model)
        {
            try
            {
                if (ModelState.IsValid)
                {
                    bool saved = clienteRepo.SalvarCliente(model);
                    if (saved)
                    {
                        return RedirectToAction("Index");
                    }
                }
                return View();
            }
            catch
            {
                return View();
            }
        }
        ...       
    }
}

No controlador ClientesController injetamos uma instância de ClientesRepository e definimos apenas os métodos para exibir, criar e persistir Clientes :

Ainda na pasta Controllers vamos criar o controlador PedidosController:

using Aspn_MasterDetail.Repositories;
using Aspn_MasterDetail.ViewModels;
using Microsoft.AspNetCore.Mvc;
namespace Aspn_MasterDetail.Controllers
{
    public class PedidosController : Controller
    {
        private readonly PedidosRepository pedidoRepo;
        public PedidosController(PedidosRepository repo)
        {
            pedidoRepo = repo;
        }
        public IActionResult Lista()
        {
            var listaPedidos = pedidoRepo.GetPedidosView();
            return View(listaPedidos);
        }
        public ActionResult Create()
        {
            var pedido = pedidoRepo.CriaPedido();
            return View(pedido);
        }
        public ActionResult Index(int clienteId)
        {
            if (clienteId > 0)
            {
                    var model = pedidoRepo.GetClientePedidosView(clienteId);
                    return View(model);
            }
            return BadRequest();
        }
        [HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult Index(ClientePedidosViewModel model)
        {
            if (ModelState.IsValid)
            {
                if (model.Pedidos != null)
                {
                    pedidoRepo.SalvarPedidos(model.Pedidos);
                }
                return View(model);
            }
            return BadRequest();
        }
    }
}

No controlador PedidosController após incluir via injeção de dependência uma instância da classe PedidosRepository, definimos os métodos para exibir e criar e persistir Pedidos :

Ao final teremos na pasta Controllers os controladores: HomeController, ClientesController e PedidosController.

Agora podemos criar as views para cada controlador antes vamos ajustar o código no arquivo _Layout.cshtml na pasta /Views/Shared incluindo links para exibir opções para acessar Clientes e Pedidos :

...
<header>
        <nav class="navbar navbar-expand-sm navbar-toggleable-sm navbar-light bg-white border-bottom box-shadow mb-3">
            <div class="container">
                <a class="navbar-brand" asp-area="" asp-controller="Home" asp-action="Index">Vendas</a>
                <button class="navbar-toggler" type="button" data-toggle="collapse" data-target=".navbar-collapse" aria-controls="navbarSupportedContent"
                        aria-expanded="false" aria-label="Toggle navigation">
                    <span class="navbar-toggler-icon"></span>
                </button>
                <div class="navbar-collapse collapse d-sm-inline-flex flex-sm-row-reverse">
                    <ul class="navbar-nav flex-grow-1">
                        <li class="nav-item">
                            <a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="Index">Home</a>
                        </li>
                        <li class="nav-item">
                            <a class="nav-link text-dark" asp-area="" asp-controller="Clientes" asp-action="Index">Clientes</a>
                        </li>
                        <li class="nav-item">
                            <a class="nav-link text-dark" asp-area="" asp-controller="Pedidos" asp-action="Lista">Pedidos</a>

                        </li>
                    </ul>
                </div>
            </div>
        </nav>
    </header>
...

As linhas em azuis foram incluídas de forma a obter o seguinte leiaute:

No link Clientes vamos acionar o controlador Clientes e a Action Index e no link Pedidos vamos acionar o controlador Pedidos e a Action Lista.

A seguir vamos criar essas duas views começando com a view Index. Para criar a view clique com o botão direito do mouse na Action Index do controlador ClientesController e na janela Add MVC View informe os dados conforme abaixo:

Ao clicar no botão Add teremos o arquivo Index.cshtml criado na pasta /Views/Clientes:

@model IEnumerable<Aspn_MasterDetail.ViewModels.ClienteExibeViewModel>
@{
    ViewBag.Title = "Lista de Clientes";
}
<h2>Clientes</h2>
<p>
    @Html.ActionLink("Criar Novo Cliente", "Create")
</p>
<table class="table">
    <tr>
        <th>@Html.DisplayNameFor(model => model.ClienteId)</th>
        <th>@Html.DisplayNameFor(model => model.Nome)</th>
        <th>@Html.DisplayNameFor(model => model.Email)</th>
        <th></th>
   </tr>
    @foreach (var item in Model)
    {
        <tr>
            <td>@Html.DisplayFor(modelItem => item.ClienteId)</td>
            <td>@Html.DisplayFor(modelItem => item.Nome)</td>
            <td>@Html.DisplayFor(modelItem => item.Email)</td>
            <td>
                @Html.ActionLink("Pedidos", "Index", "Pedidos", new { clienteId = item.ClienteId }, null)
                @*@Html.ActionLink("Details", "Details", new { id = item.ClienteId }) |
                @Html.ActionLink("Delete", "Delete", new { id = item.ClienteId })*@
            </td>
        </tr>
    }
</table>

No código gerado temos uma view tipada para exibir uma lista de objetos ClienteExibeViewModel.(A exibição do clienteId não seria necessária) 

Fizemos um ajuste para exibir o link Pedidos e acionar o controlador Pedidos e action Index que vai exibir os pedidos do cliente selecionado pelo seu código.

Abaixo temos a view exibida:

Agora vamos criar a view Index do controlador Pedidos seguindo o mesmo procedimento. Ao final teremos a view Index.cshtml criada na pasta /Views/Pedidos.

Nesta a view o código gerado vai precisar se ajustado pois queremos exibir os pedidos do cliente:

@model Aspn_MasterDetail.ViewModels.ClientePedidosViewModel

@{
    ViewBag.Title = "Index";
}

<h2>Cliente - Pedidos</h2>

@using (Html.BeginForm())
{
    @Html.AntiForgeryToken()

    <div class="form-horizontal">
        <div class="form-group">
            @Html.LabelFor(model => model.ClienteId, new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.ClienteId, new { htmlAttributes = new { @class = "form-control", @readonly = "readonly" } })
            </div>
        </div>
        <div class="form-group">
            @Html.LabelFor(model => model.ClienteNome, new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.ClienteNome, new { htmlAttributes = new { @class = "form-control", @readonly = "readonly" } })
            </div>
        </div>
        <div class="form-group">
            @Html.LabelFor(model => model.Email, new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.Email, new { htmlAttributes = new { @class = "form-control", @readonly = "readonly" } })
            </div>
        </div>
        <div class="row">
            <div class="col-md-offset-1 col-md-11">
                <table class="table">
                    <tr>
                        <th>@Html.DisplayNameFor(model => model.Pedidos[0].PedidoId)</th>
                        <th>@Html.DisplayNameFor(model => model.Pedidos[0].DataPedido)</th>
                        <th>@Html.DisplayNameFor(model => model.Pedidos[0].Descricao)</th>
                    </tr>
                    @if (Model.Pedidos != null)
                    {
                        for (var i = 0; i < Model.Pedidos.Count(); i++)
                        {
                            <tr>
                            @Html.HiddenFor(x => Model.Pedidos[i].ClienteId)
                            <td>
                            @Html.TextBoxFor(x => Model.Pedidos[i].PedidoId, new { @class = "form-control", @readonly = "readonly" })
                            </td>
                            <td>
                            @Html.TextBoxFor(x => Model.Pedidos[i].DataPedido, new { @class = "form-control", @readonly = "readonly" })
                            </td>
                            <td>
                             @Html.TextBoxFor(x => Model.Pedidos[i].Descricao, new { @class = "form-control" })
                            </td>
                            </tr>
                        }
                    }
                    @*<tr>
                       <td>
                          @Html.ActionLink("Add", "Edit", new { clienteId = Model.ClienteId, pedidoId = Model.PedidoId }, htmlAttributes: new { @class = "btn btn-success" })
                       </td>
                    <td></td>
                    <td></td>
                 </tr>*@

                </table>
            </div>
        </div>

        <div class="form-group">
            <div class="col-md-offset-1 col-md-11">
                <input type="submit" value="Salvar" class="btn btn-primary" />
            </div>
        </div>
    </div>
}

Para isso incluímos o código destacado em azul onde verificamos se o objeto Pedidos é diferente de null e percorremos a lista de objetos exibindo cada pedido do cliente.

Abaixo vemos o resultado para um cliente selecionado:

Aqui o usuário poderá alterar apenas a descrição do pedido (isso fica a critério do projeto), e, ao clicar no botão Salvar os dados serão persistidos e o pedido será alterado.

Faltou implementar as demais funcionalidades mas o objetivo era mostrar como carregar os pedidos relacionados do cliente e poder alterar a informação do pedido.

Para as demais implementações basta criar as demais viewmodels e seguir a mesma lógica.

Pegue o projeto completo aqui:  Aspn_MasterDetail.zip

"Abraão, vosso pai, exultou por ver o meu dia, e viu-o, e alegrou-se.
Disseram-lhe, pois, os judeus: Ainda não tens cinqüenta anos, e viste Abraão?
Disse-lhes Jesus: Em verdade, em verdade vos digo que antes que Abraão existisse, eu sou."

João 8:56-58

Referências:


José Carlos Macoratti