ASP.NET Core - Exibindo e atualizando dados relacionados


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

Exibir e atualizar dados relacionados em uma aplicação ASP .NET Core MVC pode ser uma tarefa muito complexa msmo tendo à disposição os assistentes do Visual Studio, pois geralmente, essa tarefa requer que alguns ajustes sejam feitos para que tudo funcione corretamente.

Assim, esse tutorial vai abordar de forma prática vários conceitos da ASP .NET Core e do EF Core, de forma que você poderá exercitar e por em prática os seus conhecimentos.

A seguir temos um roteiro do que iremos apresentar neste tutorial:

  1. Criar um projeto no VS 2019 usando o template ASP .NET Core Web Application;
  2. Definir um cenário onde temos que realizar o mapeamento das entidades para um relacionamento muitos para muitos usando o EF Core. Como exemplo iremos definir as entidades :  Cliente,  Pedido, Item e ItemPedido;
  3. Definir um relacionamento de um para muitos entre Cliente e Pedido e de muitos para muitos entre Pedido e Item usando o EF Core;
  4. Criar a classe de contexto, definir a string de conexão e registrar contexto como um serviço;
  5. Criar as ViewModels para exibir e editar Clientes e exibir e editar Pedidos;
  6. Definir um repositório para Clientes e Pedidos;
  7. Criar os controladores ClientesController e PedidosController;
  8. Realizar a exibição dos Clientes e seus Pedidos e permitir a atualização;

Vemos assim que temos muitos conceitos envolvidos neste projeto.

Criando o projeto ASP .NET Core MVC

Abra o Visual Studio 2019 Community e clique em New Project:

No menu File selecione Add -> New Project;

A seguir selecione :

Escolha o template ASP .NET Core Web Application e clique em Next :

A seguir informe o nome Aspn_MasterDetail e clique em Create.

Selecione .NET Core e ASP .NET Core 2.2 e o template Web Application (Model-View-Controller) e clique em Create.

Ao final teremos o nosso projeto criado e pronto para ser usado.

Definindo o relacionamento entre as entidades

A primeira grande tarefa que iremos realizar e criar uma pasta Models no projeto e nesta pasta criar as classes que representam o nosso modelo de domínio:

1- Cliente

    public class Cliente
    {
        public Cliente()
        {
            Pedidos = new HashSet<Pedido>();
        }
        public int ClienteId { get; set; }
        [Required]
        [MaxLength(100)]
        public string Nome { get; set; }
        [MaxLength(150)]
        public string Email { get; set; }
        public virtual ICollection<Pedido> Pedidos { get; set; }
    }

Estamos usando atributos Data Annotations para validar algumas propriedades da nossa entidade e definindo a propriedade de navegação para indicar o relacionamento um para muitos entre Cliente e Pedidos.

1- Pedido

    public class Pedido
    {
        public int PedidoId { get; set; }
        [Required]
        [DataType(DataType.Date)]
        [DisplayFormat(DataFormatString = "{0:dd-MM-yyyy}", ApplyFormatInEditMode = true)]
        public DateTime DataPedido { get; set; }
        [Required]
        [MaxLength(200)]
        public string Descricao { get; set; }
        public virtual Cliente Cliente { get; set; }
        [Required]
        public int ClienteId { get; set; }
        public virtual ICollection<ItemPedido> ItensPedido{ get; set; }
    }

1- Item

    public class Item
    {
        public int ItemId { get; set; }

        [MaxLength(150)]
        public string Descricao { get; set; }

        public int Quantidade { get; set; }

        [Column(TypeName = "decimal(18,2)")]
        public decimal Preco { get; set; }

        public ICollection<ItemPedido> ItensPedidos { get; set; }
    }

1- ItemPedido

    public class ItemPedido
    {
        public virtual int PedidoId { get; set; }
        public virtual Pedido Pedido { get; set; }
        public virtual int ItemId { get; set; }
        public virtual Item Item { get; set; }
    }

A entidade ItemPedido é usada para definir o relacionamento muitos-para-muitos entre as entidades Pedido e Item. A partir dela será criada a tabela de junção para definir o relacionamento muitos para muitos.

A seguir vamos criar a pasta Context no projeto e nesta pasta criar a classe de contexto AppDbContext e definir o mapeamento entre as entidades e as tabelas e definir relacionamento usando a Fluente API.

1- AppDbContext

using Aspn_MasterDetail.Models;
using Microsoft.EntityFrameworkCore;
namespace Aspn_MasterDetail.Context
{
    public class AppDbContext : DbContext
    {
        public AppDbContext(DbContextOptions<AppDbContext> options)
          : base(options)
        { }
        public DbSet<Cliente> Clientes { get; set; }
        public DbSet<Pedido> Pedidos { get; set; }
        public DbSet<Item> Itens { get; set; }
        public DbSet<ItemPedido> ItensPedido { get; set; }
        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            modelBuilder.Entity<ItemPedido>()
                .HasKey(bc => new { bc.PedidoId, bc.ItemId });
            modelBuilder.Entity<ItemPedido>()
                .HasOne(bc => bc.Pedido)
                .WithMany(b => b.ItensPedido)
                .HasForeignKey(bc => bc.PedidoId);
            modelBuilder.Entity<ItemPedido>()
                .HasOne(bc => bc.Item)
                .WithMany(c => c.ItensPedidos)
                .HasForeignKey(bc => bc.ItemId);
        }
    }
}

A chave primária para a tabela de junção - ItensPedido -  é uma chave composta que compreende ambos os valores de chave estrangeira. Além disso, ambos os lados do relacionamento muitos-para-muitos são configurados usando os métodos HasOne, WithMany e HasForeignKey da Fluent API.

No arquivo Startup vamos registrar o contexto como um serviço, e, definir o provedor do banco de dados Sql Server que iremos usar, no método ConfigureServices:

    public void ConfigureServices(IServiceCollection services)
        {
            services.Configure<CookiePolicyOptions>(options =>
            {
                options.CheckConsentNeeded = context => true;
                options.MinimumSameSitePolicy = SameSiteMode.None;
            });

            services.AddDbContext<AppDbContext>(options =>
              options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));

            services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
        }

A seguir no arquivo appsettings.json vamos definir a string de conexão com o banco de dados

{
  "ConnectionStrings": {
    "DefaultConnection": "Data Source=MACORATTI;Initial Catalog=DemoMasterDetail;Integrated Security=True"
  },
  "Logging": {
    "LogLevel": {
      "Default": "Warning"
    }
  },
  "AllowedHosts": "*"
}

Aplicando o Migrations

Aplicando o migrations na janela de Package Manager Console primeiro criamos a migração:

add-migration Inicial

A seguir com o script de migração criado aplicamos a migração usando o comando:  update-database

Abrindo o SQL Server Management Studio veremos o banco de dados DemoMasterDetail e as tabelas criadas:

E o relacionamento entre as tabelas definido conforme mostra o diagrama abaixo:

Criando as ViewModels

Vamos criar uma pasta ViewModels no projeto e nesta pasta definir as ViewModels usadas no projeto.

1- ClienteExibeViewModel

Vamos usar esta ViewModel para exibir os dados dos clientes na View:

    public class ClienteExibeViewModel
    {
        [Display(Name = "Código")]
        public int ClienteId { get; set; }
        [Display(Name = "Nome")]
        public string Nome { get; set; }
        [Display(Name = "Email")]
        public string Email { get; set; }
    }

Novamente usamos os atributos Data Annotations nas propriedades da ViewModel.

Temos também a view model ClienteEditaViewModel que possui o código igual a essa view model porque estou usando um modelo muito simples.

2 - PedidoExibeViewModel

Vamos usar esta ViewModel para exibir os dados dos pedidos na View:

    public class PedidoExibeViewModel
    {
        [Display(Name = "Cliente")]
        public string NomeCliente { get; set; }
        [Display(Name = "No. do Pedido")]
        public int PedidoId { get; set; }
        [Display(Name = "Data do Pedido")]
        public DateTime DataPedido { get; set; }
        [Display(Name = "Descrição")]
        public string Descricao { get; set; }
    }

Temos também a view model PedidoEditaViewModel que possui o código igual a essa view model porque estou usando um modelo muito simples.

3- ClientePedidosViewModel

Esta view model vai exibir o cliente e seus pedidos.

    public class ClientePedidosViewModel
    {
        [Display(Name = "Código")]
        public int ClienteId { get; set; }
        [Display(Name = "Nome")]
        public string ClienteNome { get; set; }
        [Display(Name = "Email")]
        public string Email { get; set; }
        public List<PedidoExibeViewModel> Pedidos { get; set; }
    }

Nesta view model temos uma lista de pedidos do tipo PedidoExibeViewModel.

Na próxima parte do artigo vamos continuar criando os repositórios.

"Eu sou o Alfa e o Ômega, o princípio e o fim, diz o Senhor, que é, e que era, e que há de vir, o Todo-Poderoso."
Apocalipse 1:8

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 ?

Quer aprender a criar aplicações Web Dinâmicas usando a ASP .NET MVC 5 ?

Referências:


José Carlos Macoratti