EF Core - Sistema de Vendas : Usando a Fluent API


 Neste artigo eu vou mostrar como usar os recursos da Fluent API com EF Core em um projeto Console.


Ao trabalhar com a abordagem Code First usando o Entity Framework o comportamento padrão é mapear suas classes POCO para tabelas usando um conjunto de convenções nativas do EF. Às vezes, no entanto, você não pode ou não quer seguir essas convenções e precisa mapear entidades para algo diferente do que as convenções ditam.



Existem duas maneiras de realizar a configuração e o mapeamento no EF quando você não deseja seguir as convenções padrão: Data Annotations e Fluent API.

1- Data Annotations - Utiliza atributos para realizar o mapeamento e configuração;
2- Fluent API - Fornece mais funcionalidades que o Data Annotations

Na abordagem Code First a Fluent API é mais acessada sobrescrevendo o método OnModelCreating no seu DbContext.
 

A Fluent API suporta os seguintes tipos de mapeamentos:

 

Mapeamento Para o Banco de dados

Model-wide Mapping

- Define o esquema padrão

- Define as convenções padrão

Entity Mapping

- Para única ou múltiplas tabelas e esquema

- Para Tipo Completo

- Para hierarquia de herança

Property Mapping

- Para Coluna, Nome da coluna, tipo de coluna,
coluna Nullabe(anulável) ou não NULL coluna
,
- O tamanho das colunas, ordem das colunas

- Para coluna concorrência

- Para coluna chave estrangeira

- Para configurar relacionamentos

Neste artigo eu vou mostrar como usar a Fluent API para definir o mapeamento entre as classes do domínio da aplicação e as tabelas do banco de dados.

Recursos usados:

Definindo o cenário

Vamos simular um cenário para um sistema de Vendas focando nos pedidos onde temos as seguintes entidades definidas: Pedidos, Itens, Clientes e Produtos

Na figura abaixo temos a representação das entidades e seus atributos e também do relacionamento entre as entidades.

Relacionamentos:

  1. A entidade Pedidos possui um relacionamento de um para muitos para a entidade Itens

  2. A entidade Clientes possui um relacionamento de um para muitos para a entidade Pedidos

  3. A entidade Produtos possui um relacionamento de um para muitos para a entidade Itens   

Essa seria uma visão a nível de entidades, conjunto de entidade, atributos e relacionamentos do modelo entidade relacionamento (MER) que esta baseado em uma percepção do mundo real para expressar um sistema de vendas.

Vamos partir deste cenário mas vamos usar a abordagem Code-First do EntityFramework Core e nesta abordagem ao invés de iniciar criando o banco de dados vamos nos concentrar no domínio da aplicação e vamos começar criando as classes e definir as propriedades das classes que representam os atributos e também vamos definir as associações entre as classes que representam os relacionamentos.

A seguir vamos aplicar o Migrations do EF Core para criar o banco de dados e as tabelas relacionadas com as classes definidas no domínio.

Assim usando a abordagem Code-First do EF Core vamos tratar com:

O mapeamento entre as classes e suas propriedades e as tabelas serão feitas usando a Fluent API.

Como nosso objetivo é focar na utilização da Fluent API vamos criar um projeto do tipo Console e definir neste projeto as classes, configurações e mapeamentos.

Em um projeto usando as boas práticas usaríamos uma arquitetura desacoplada  criando projetos separados conforme a responsabilidade de cada projeto. A seguir, apenas para constar, temos uma sugestão de arquitetura que pode ser usada.

  1. Domain - Contém as entidades do domínio da aplicação e validações relacionadas;

  2. Application - Contém as interfaces e casos de uso da aplicação que permitem acessar o domínio e implementam a lógica de negócio;

  3. Infrastructure - Contém os recursos para definir a lógica de acesso a dados, repositórios, etc.;

  4. CrossCutting - Contém as definições e configurações dos serviços e recursos usados nos projetos da solução;

  5. Pedidos - Representa a camada de apresentação que vai interagir com os demais projetos;

Os projetos Domain, Application, Infrastructure e CrossCutting seriam projetos do tipo Class Library (.NET 5.0) e o projeto Pedidos seria o projeto do tipo Console (.NET 5.0).

Criando o projeto no VS 2019

Abra o VS 2019 e clique em New Project;

A seguir  selecione o template Console Application e clique em Next;

Informe o nome do projeto Vendas e sua localização.

A seguir selecione o Target Framework como .NET 5.0 (Current) conforme figura abaixo:

Clique em Create.

Vamos iniciar incluindo as referências aos seguintes pacotes do EF Core neste projeto:

Para incluir os pacotes use o menu Tools->..-> Manage Nuget Packages for Solution e na guia Browse selecione e instale os pacotes ou abra a janela Package Manager Console e digite o comando: install-package <nome-pacote>

Pronto já temos o projeto Console criado e pronto para ser usado usando o EF Core.

No projeto vamos criar uma pasta chamada Entities e nesta pasta criar as entidades que representam o nosso modelo de domínio representando pelas classes:

  1. Pedido
  2. Cliente
  3. Item
  4. Produto

Vamos usar também duas enumerações definidas nos arquivos : StatusPedido e TipoFrete

Aqui devemos decidir quais as propriedades e comportamentos nosso domínio vai possuir. Para não tornar o exemplo muito longo e maçante eu vou definir um modelo de domínio bem simples.

A seguir temos o código das entidades e das enumerações:

1- Pedido

using System;
using System.Collections.Generic;
namespace Domain.Entities
{
    public class Pedido
    {
        public int PedidoId { get; set; }
        public int ClienteId { get; set; }
        public DateTime DataPedido { get; set; }
        public DateTime DataEntrega { get; set; }
        public TipoFrete Frete { get; set; }
        public StatusPedido Status { get; set; }
        public ICollection<Item> Itens { get; set; }
        public Cliente Cliente { get; set; }
    }
}

2- Cliente

using System.Collections.Generic;
namespace Domain.Entities
{
    public class Cliente
    {
        public int ClienteId { get; set; }  
        public string Nome { get; set; }
        public string Email { get; set; }
        public string Telefone { get; set; }
        public string Cep { get; set; }
        public string Cidade { get; set; }
        public string Estado { get; set; }
        public ICollection<Pedido> Pedidos { get; set; }
    }
}

3- Item

 public class Item
    {
        public int ItemId { get; set; }
        public int PedidoId { get; set; }
        public int ProdutoId { get; set; }
        public int Quantidade { get; set; }
        public decimal Preco { get; set; }
        public Pedido Pedido { get; set; }
        public Produto Produto { get; set; }
    }

4- Produto

using System.Collections.Generic;
namespace Domain.Entities
{
    public class Produto
    {
        public int ProdutoId { get; set; }
        public string Nome { get; set; }
        public string Descricao { get; set; }
        public decimal Preco { get; set; }
        public bool Ativo { get; set; }
        public ICollection<Item> Itens { get; set; }
    }
}

5- StatusPedido

 public enum StatusPedido
    {
        Analise,
        Finalizado,
        Entregue
    }

6- TipoFrete

 public enum TipoFrete
    {
        CIF,
        FOB,
        SemFrete
    }

Incluindo um Class Diagram em nosso projeto iremos obter o seguinte diagrama exibindo os objetos criados no projeto Domain:

Na segunda parte do artigo vamos continuar definindo o mapeamento das classes usando a Fluente API.

"Voz do que clama no deserto: Preparai o caminho do Senhor; endireitai no ermo vereda a nosso Deus.
Todo o vale será exaltado, e todo o monte e todo o outeiro será abatido; e o que é torcido se endireitará, e o que é áspero se aplainará."
Isaías 40:3,4

Referências:


José Carlos Macoratti