EF6 - Criando um relacionamento mestre-detalhe usando Code-First


 Neste artigo eu vou mostrar como podemos criar um relacionamento mestre-detalhes usando o Entity Framework 6 com uma abordagem Code-First.

   

Eu já escrevi diversos artigos sobre os recursos do Entity Framework e a abordagem Code-First. A maior parte deles usando as versões 4.0 e 4.1.

Como estamos na versão 6.2 estou voltando ao tema para mostrar como criar um relacionamento mestre-detalhes usando o EF 6 na abordagem Code-First.

Neste artigo eu vou mostrar como podemos criar duas entidades, definir o relacionamento entre elas, incluir informações na entidade mestre e seus respectivos detalhes na entidade detalhe.

Você verá a criação do banco de dados e das tabelas de forma personalizada diretamente usando classes POCO na abordagem Code-First usando a linguagem C# em uma aplicação Windows Forms.

Para simplificar o artigo eu vou criar um único projeto Windows Forms referenciando o Entity Framework e definindo as entidades neste projeto. Para uma aplicação de produção o conselho é criar outro projeto onde as classes e as referências ao Entity Framework deverão ser definidas.

Recursos usados:

Criando o projeto no VS 2013 Express for Windows desktop

Abra O Visual Studio 2013 Express for Windows desktop e clique em new Project;

Selecione a linguagem C# e o template Windows Forms Application informando o nome EF_MestreDetalhes e clique no botão OK;

A seguir clique no menu TOOLS -> Nuget Package Manager -> Manage Nuget Package for Solution...

Na janela do assistente informe - entity framework - na caixa de busca e selecione o respectivo pacote e clique no botão Install;

Concluída esta etapa já teremos a referência ao entity framework em nosso projeto.

Vamos então criar as nossas classes POCO a partir das quais teremos a criação das entidades e suas respectivas tabelas mapeadas pelo EF.

Vamos criar duas classes :

  1. Pedido
  2. PedidoDetalhe

Vamos definir nas classes a associação existente entre as entidades de forma que o EF possa inferir o relacionamento entre as tabelas mapeadas.

No menu PROJECT clique em Add Class e informe o nome Pedido.cs. A seguir defina o seguinte código nesta classe:

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace EF_MestreDetalhes
{
    [Table("Pedido")]
    public class Pedido
    {
        public int Id { get; set; }        
        [MaxLength(100)]
        public string Cliente { get; set; }
        public DateTime DataPedido { get; set; }
        public decimal Total { get; set; }
        [MaxLength(5)]
        [Column(TypeName = "varchar")]
        public string Status { get; set; }
        public IEnumerable<PedidoDetalhe> PedidoDetalhes { get; set; }
    }
}

Repita o procedimento e crie a classe PedidoDetalhe.cs e defina o código abaixo nesta classe:

using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace EF_MestreDetalhes
{
    [Table ("PedidoDetalhe")]
    public class PedidoDetalhe
    {
        public int Id { get; set; }
        public Pedido Pedido { get; set; }
        [MaxLength(65)]
        public string Produto { get; set; }
        public int Valor { get; set; }
        public decimal PrecoUnitario { get; set; }
    }
}

Note que definimos a associação entre as classes definindo a propriedade Pedido na classe PedidoDetalhe e a propriedade PedidoDetalhes na classe Pedido.

Observe também que as classes utilizam o namespace System.ComponentModel.DataAnnotations. Mas o para que serve isso ?

Os Data annotations são usados para definir atributos e validação nas classes alterando assim a convenção padrão usada pelo Entity Framework.

Os atributos Data Annotation foram introduzido no .NET 3.5 como uma forma de adicionar a validação para as classes usadas por aplicações ASP.NET. Desde aquela época, o RIA Services começou a usar anotações de dados e eles agora fazem parte do Silverlight também. No EF o Code-First permite que você construa um EDM usando código (C#/VB .NET) e também permite realizar a validação com atributos Data Annotations.

Para este recurso devemos usar o namespace System.ComponentModel.DataAnnotations pois é ele que provê atributos de classes (usados para definir metadados) e métodos que podemos usar em nossas classes para alterar as convenções padrão e definir um comportamento personalizado que pode ser usado em vários cenários.  A seguir temos a relação das principais Annotations suportadas pelo Entity Framework:

Key - Usada para especificar que uma propriedade/coluna é parte da chave primária da entidade e se aplica apenas a propriedades escalares;
StringLength - Usada para especificar o tamanho máximo de uma string;
ConcurrencyCheck - Usada para especificar que uma propriedade/coluna tem um modo de concorrência "fixed " no modelo EDM;
Required : - Usada para especificar que uma propriedade/coluna é não-nula e aplica-se a propriedades escalares, complexas, e de navegação;
Column – Usada para especificar o nome da coluna, a posição e o tipo de dados ;
Table – Usada para especificar o nome da tabela e o esquema onde os objetos da classe serão atualizados;
ForeignKey - Usado em uma propriedade de navegação para especificar a propriedade que representa a chave estrangeira da relação
DatabaseGenerated -Usada em uma propriedade para especificar como o banco de dados gera um valor para a propriedade, ou seja, Identity, Computed ou None;
NotMapped – Usada para definir que a propriedade ou classe não estará no banco de dados;

Então quando o Entity Framework encontrar as nossas definições de atributos e validações ele vai adotar a convenção que definimos e não a padrão que ele seguiria se apenas tivéssemos definidos as classes sem as anotações. Usamos os seguintes atributos na definição de nossas classes:

Definindo o Contexto

Agora vamos definir uma classe que irá usar herdar da API DbContext e referenciar as classes que acabamos de criar

No menu PROJECT selecione Add Class e a seguir informe o nome PedidoDBContexto.cs e clique no botão Add;

A seguir defina o código abaixo neste classe:

using System.Data.Entity;
namespace EF_MestreDetalhes
{
    public class PedidoDBContexto : DbContext
    {
        public PedidoDBContexto() : base("Macoratti_MestreDetalhes")
        {}
        public DbSet<Pedido> Pedidos { get; set; }
        public DbSet<PedidoDetalhe> PedidoDetalhes { get; set; }
    }
}

A nossa classe PedidoDBContexto herda de DbContext e define as propriedades Pedidos e PedidoDetalhes com as quais temos acesso as tabelas do banco de dados.

O construtor da classe  define o nome do banco de dados que será criado pelo Entity Framework.

Isso é tudo que você precisa para iniciar a persistência e a consulta aos dados. Mas podemos melhorar...

Vamos usar outro recurso do Entity Framework que é o inicializador do banco de dados onde vamos definir a criação e carga dos dados iniciais.

Como já disse o EF irá criar um banco de dados com o nome EscolaMacoratti_MestreDetalhes que definimos no construtor da classe de contexto.

Já temos tudo pronto para gerar as entidades, o banco de dados, as tabelas e o relacionamento entre elas.

Vamos agora definir no formulário form1.cs do projeto uma interface para exibir as informações que iremos incluir nas tabelas.

Inclua a partir da ToolBox os seguintes controles no formulário form1.cs:

Defina o leiaute do formulário conforme a figura abaixo:

No evento Click do botão processar inclua o código abaixo:

 private void btnProcessar_Click(object sender, EventArgs e)
 {
            criarMestreDetalhes();
 }

O método criarMestreDetalhes() possui o seguinte código:

public void criarMestreDetalhes()
        {
            using (var context = new PedidoDBContexto())
            {
                for (int i = 1; i < 6; i++)
                {
                    //cria um pedido
                    var _pedido = new Pedido
                    {
                        Cliente = "Cliente " + i,
                        DataPedido = DateTime.Now,
                        Total = 10 * i,
                        Status = "NOVO",
                    };
                    context.Pedidos.Add(_pedido);
                    //cria um detalhe do pedido
                    for (int j = 1; j < 4; j++)
                    {
                        var _pedidoDetalhe = new PedidoDetalhe
                        {
                            Valor = 10 * j + i,
                            Produto = "Produto" + j,
                            PrecoUnitario = 10 + j,
                            Pedido = _pedido
                        };
                        context.PedidoDetalhes.Add(_pedidoDetalhe);
                    }
                }
                context.SaveChanges();
                //exibe os pedidos e seus detalhes
                dgvPedido.DataSource = context.Pedidos.ToList();
                dgvDetalhes.DataSource = context.PedidoDetalhes.ToList();
            }
        }

Quando este código for executado e o comando SaveChanges() entrar em ação serão criados o banco de dados e as respectivas tabelas com os registros incluídos nas entidades.

Executando o projeto e clicando no botão Processar teremos o seguinte resultado:

Se abrirmos o SQL Server Express e dermos uma espiada no banco de dados e nas tabelas iremos verificar o seguinte:

1- O banco de dados Macoratti_MestreDetalhes foi criado e as tabelas Pedido e PedidoDetalhes foram criadas com seus respectivos campos:

2- As informações incluídas via código foram persistidas nas tabelas Pedido e PedidoDetalhes:

tabela - Pedido
tabela - PedidoDetalhes

Vimos assim o poder do Entity Framework 6 e a abordagem Code-First que gerou o banco de dados e as tabelas e que definiu o relacionamento entre elas a partir das classes POCO.

Pegue o projeto completo aqui:  EF_MestreDetalhes.zip

Já estou crucificado com Cristo; e vivo, não mais eu, mas Cristo vive em mim; e a vida que agora vivo na carne, vivo-a pela fé do Filho de Deus, o qual me amou, e se entregou a si mesmo por mim.(apóstolo Paulo)
Gálatas 2:20

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