EntityFramework CodeFirst

No post anterior, eu falei em como trabalhar com Entity Framework usando o Designer, ou seja, um modelo de classes criado a partir de um arquivo EDMX. Este modelo funciona perfeitamente em diversos tipos de projetos, mas o grande incoveniente é ter um arquivo EDMX para cada tipo de banco de dados do seu projeto.

Então vamos agora usar uma abordagem diferente, mas nem tão diferente assim do artigo anterior. Nossa necessidade ainda é manter o isolamento do banco de dados e trabalhar somente com objetos. O CodeFirst, como o próprio nome sugere, nos leva a criar primeiramente as classes POCO e depois o banco de dados, mas é possível também pegar um banco de dados existente e gerar o CodeFirst.

O Entity Framework faz uma ponte entre as classes POCO e o banco de dados utilizando um container que chamamos de Contexto. O contexto é o responsável por mapear as nossas classes com o banco de dados e também por informar ao engine quem é o banco de dados, através da string de conexão, e isto é o que mais me agrada no Code First, você precisa trocar somente a string de conexão para mudar de banco. Nenhum tipo de alteração no código é necessária.

Instalando o Entity Framework Code First:

Antes de começarmos a escrever as classes, precisamos instalar o Entity Framework CodeFirst, que é basicamente composto pela EntityFramework.DLL. Faremos isto isando o NuGet, que é um instalador de pacotes para o Visual Studio. Se você ainda não o possui, vá até o Extension Manager do Visual Studio (Tools/Extension Manager) e instale:

SNAGHTMLa23ac4a_thumb1_thumb

Depois de instalado o NuGet, vá em Tools/Library Package Manager/Package Manager Console. Isto vai abrir o gerenciador do NuGet:

image_thumb1_thumb

Agora digite o comando: Install-Package EntityFramework dentro do console, isto irá instalara o EF CodeFirst e suas dependências:

Criando um projeto com o EntityFramework CodeFirst:

Vamos criar uma classe de contexto que chamaremos de Contexto.cs, esta classe irá herdar de DbContext e nela iremos mapear nossas tabelas:

   1: using System;

   2: using System.Collections.Generic;

   3: using System.Linq;

   4: using System.Text;

   5: using System.Data.Entity;

   6:  

   7: namespace EFCodeFirst

   8: {

   9:     public class Contexto : DbContext

  10:     {

  11:         public DbSet<Grupo> Grupo { get; set; }

  12:         public DbSet<Produto> Produto { get; set; }

  13:     }

  14: }

O segredo aqui é o DBSet<>, pois ele faz o mapeamento da nossa classe para o banco e vincula a um objeto, que utilizaremos para fazer as operações com o BD.

Veja o código da classe Grupo:

   1: using System;

   2: using System.Collections.Generic;

   3: using System.Linq;

   4: using System.Text;

   5: using System.ComponentModel.DataAnnotations;

   6:  

   7: namespace EFCodeFirst

   8: {

   9:     [Table("Grupo")]

  10:     public class Grupo

  11:     {

  12:         public int ID { get; set; }

  13:         [Required(ErrorMessage="Nome não pode ser branco.")]

  14:         public string Nome { get; set; }

  15:  

  16:         public virtual IQueryable<Produto> Produtos { get; set; }

  17:     }

  18: }

E da classe Produto:

   1: using System;

   2: using System.Collections.Generic;

   3: using System.Linq;

   4: using System.Text;

   5: using System.ComponentModel.DataAnnotations;

   6:  

   7: namespace EFCodeFirst

   8: {

   9:     [Table("Produto")]

  10:     public class Produto

  11:     {

  12:         public int ID { get; set; }

  13:         [Required(ErrorMessage="Nome não pode ser branco.")]

  14:         public string Descricao { get; set; }

  15:         public int GrupoID { get; set; }

  16:  

  17:         [ForeignKey("GrupoID")]

  18:         public virtual Grupo Grupo { get; set; }

  19:     }

  20: }

No CodeFirst podemos controlar todos os aspectos do mapeamento das classes com o banco de dados, desde o nome da tabela no banco, obrigatoriedade dos campos, tamanho, etc.

Na classe Grupo, eu determinei o nome da tabela no banco de dados (linha 9), ou seja, podemos ter um nome para a classes e outro para a tabela no banco de dados. Informei também que o nome não pode ser banco e vinculei uma mensagem, que pode ser usada em projetos MVC e WPF (linha 13). Finalmente criei o relacionamento entre Grupo e Produto (linha 16).

Na classe Produto, eu determinei também o nome da tabela no banco de dados, e o campo obrigatório. Fiz também o relacionamento com a tabela grupo através do campo GrupoID (linhas 15 e 17,18).

O EF identifica também automaticamente as chaves primárias das tabelas, desde que você as chame por ID ou nome_da_tabelaID, exemplo: GrupoID ou ProdutoID.

Um coisa muito legal que o EF CodeFirst faz para nós é criar o banco de dados, mas isto depende do provider do seu banco de dados, nem todos aceitam a criação do banco.

Vamos agora montar um exemplo para carregar dados no nosso banco:

   1: using System;

   2: using System.Collections.Generic;

   3: using System.Linq;

   4: using System.Text;

   5:  

   6: namespace EFCodeFirst

   7: {

   8:     class Program

   9:     {

  10:         static void Main(string[] args)

  11:         {

  12:             var db = new Contexto();

  13:  

  14:             db.Database.CreateIfNotExists();

  15:  

  16:             var g1 = new Grupo() { Nome = "Peças" };

  17:             var g2 = new Grupo() { Nome = "Serviços" };

  18:  

  19:             db.Grupo.Add(g1);

  20:             db.Grupo.Add(g2);

  21:  

  22:             var p1 = new Produto() { Descricao = "Pneu", Grupo = g1 };

  23:             var p2 = new Produto() { Descricao = "Roda", Grupo = g1 };

  24:             var p3 = new Produto() { Descricao = "Alinhamento", Grupo = g2 };

  25:             var p4 = new Produto() { Descricao = "Balanceamento", Grupo = g2 };

  26:  

  27:             db.Produto.Add(p1);

  28:             db.Produto.Add(p2);

  29:             db.Produto.Add(p3);

  30:             db.Produto.Add(p4);

  31:  

  32:             db.SaveChanges();

  33:  

  34:             var dados = from p in db.Produto

  35:                         select p;

  36:  

  37:             foreach (var linha in dados)

  38:             {

  39:                 Console.WriteLine("{0,-30} - {1}", linha.Grupo.Nome, linha.Descricao);

  40:             }

  41:  

  42:         }

  43:     }

  44: }

O código acima cria o nosso banco de dados no SQL, caso ele não exista (linha 14). Após isto eu inseri os dados em Grupo e Produto, mas percebam que eu simplesmente vinculei os objetos, sem me preocupar com as chaves primárias ou estrangeiras, pois o EF resolve isto para nós desde que seu mapeamento esteja correto.

Assim ao final do código temos o banco de dados criado e os dados inseridos. Veja como ficou o banco de dados no Management Studio:

image_thumb3_thumb1

Veja que o nome do banco de dados é o nome da aplicação mais o nome do Contexto, mas podemos resolver isto adicionando um arquivo App.Config e informando os dados do banco, então vamos adicionar um arquivo de configuração ao nosso exemplo e colocar a seguinte linha:

   1: <?xml version="1.0" encoding="utf-8" ?>

   2: <configuration>

   3:   <connectionStrings>

   4:     <add name ="Contexto" providerName="System.Data.SqlClient" connectionString="data source=(local); initial catalog=ExemploEF; user id=teste; password=teste;"/>

   5:   </connectionStrings>

   6: </configuration>

O nome da string de conexão é o mesmo nome da nossa classe de Contexto. O providerName indica que usamos SQL Server e a string de conexão é padrão de ADO.Net, informando Servidor/Banco de Dados/Usuário. Eu já fiz outro post falando só sobre Gerenciamento de Strings de Conexão.

Executando nosso código novamente o banco chamado EFExemplo será criado e preenchido com os dados.

Visualizando o modelo do CodeFirst:

Mas e se você quiser ver como está ficando seu modelo se você está usando somente código ? Para isto existe o Entity Framework PowerTools que permite visualizar o modelo a partir das classes e também gerar um script para o banco de dados. Vejamos como ver o modelo visual do nosso exempo.

Após instalar o PowerTools, clique com o botão direito do mouse sobre a classe Contexto.cs no seu projeto, irá aparecer um menu de contexto EntityFramework, com várias opções:

image_thumb5_thumb1

A primeira opção é justamente a que mostra o modelo gráfico, vamos vê-lo então:

image_thumb3[1]

Já tenho um banco de dados e quero usar o CodeFirst:

Se você já tiver um banco de dados, o EF PowerTools permite que você faça engenharia reversa e gere o contexto e as classes, para isto clique com o botão direito do mouse em sua Solution no Visual Studio e escolhar Entity Framework no menu:

image_thumb9_thumb1

Esta opção gera todas as classes e relacionamentos do seu modelo, basta informar qual o banco de dados e o servidor na janela abaixo:

SNAGHTMLa560840_thumb1_thumb1

Não se esquece de adicionar o EntityFramework CodeFirst com o NuGet antes de fazer a engenharia reversa.

Quando usar Designer ou CodeFirst:

Esta é um pergunta bem complicada, eu diria que se você usa somente um banco de dados e precisa trabalhar com Stored Procedures é melhor usar o Designer, principalmenet porquê o CodeFirst ainda não suporta procedures nativamente.

Se você quer criar uma aplicação multibanco, de maneira mais rápida e simples através de classes POCO, então o CodeFirst é sua escolha.

Muito importante saber também que o Entity Framework Designer e o CodeFirst são independentes e podem não compartilhar alguns recursos.

Espero que o artigo seja útil para vocês e se assim desejarem façam seus comentários ou sugestões.

Até a próxima,
Carlos dos Santos.

16 Comments

  1. Muito boa explicação e didática.

  2. Roberto says:

    Parabéns Carlos pelos excelentes artigos.
    Apesar de atuar na área por vários anos estou tentando migrar os meus sistemas para o C# e estava em duvida em qual framework usar mas, depois de ler os seus posts vou usar com certeza o Entity Framework Code First.
    Voce falou em um deles que caso tenha só um banco de dados não precisaria utilizar as classes POCO, mas isto não geraria problema no futuro?
    Também penso em criar a minha aplicação em 3 camadas (BLL,DAL e UI) voce pensa em escrever algum posto sobre isto?
    []s, Roberto

    • Carlos dos Santos says:

      Olá Roberto,
      Fico muito contente que meus artigos estão lhe ajudando e assim que voltar do MVP Summit, vou escrever mais artigos e 3 camadas será um deles.
      []s,
      Carlos.

  3. Ortega says:

    Não consigo pensar em uma aplicação corporativa robusta que crie um banco de dados assim, “on demand”, a partir do aplicativo… Onde trabalho há uma equipe de analistas altamente qualificada que modela as bases de dados. Ainda que exista um trabalho em equipe entre o arquiteto e seu modelo OO e os analistas, e ainda que o modelo OO surja primeiro – o que é o ideal, a meu ver – chegar neste ponto de gerar tudo a partir da aplicação é um esforço desnecessário – que pode sacrificar a performance da aplicação.

    • Carlos dos Santos says:

      Ortega,
      Isto depende muito do seu modelo de desenvolvimento. O que você faz primeiro: o banco ou as regras ? Se for o banco, tem sentido o que você está falando e neste caso você faz um engenharia reversa com o EF PowerTools e traz o banco para o CodeFirst. Mas existe uma outra maneira que é modelar as classes, testar usando um mock ou db fake e só depois criar o banco.
      Tudo depende do seu modelo.
      []s,
      Carlos.

  4. Eric says:

    Carlos,
    Estou com um problema. Se houver algum problema no INSERT, após o SaveChanges(), se retornar um erro, ele não insere porém eu acabo “perdendo” o ID. Ex.: Se o registro fosse o primeiro a ser inserido, quando houvesse sucesso no INSERT ele não seria ID=1. Como resolvo isso?

  5. Carlos dos Santos says:

    Olá,
    Até onde testei o Identity, quem está incrementando é o banco de dados e não o Entity, sendo assim, não existe uma maneira de impedir o incremento após um INSERT.
    []s,

  6. Rafael Augusto says:

    Olá Carlos

    Nesse seu artigo você está usando o Data Annotations certo?. Eu fiz engenahria reversa usando o EF PowerTools e ele criou uma classe de mapeamento pareciado com o fluent NHibernate. A minha duvida é:
    1- O EF PowerTools não tinha que gerar as entitdades com os Data Annotations???
    2 – Posso usar tanto um quando o outro???

  7. Carlos dos Santos says:

    Rafael,
    O PowerTools gera somente com Fluent, não com DataAnnotations. Você pode usar qualquer um, a vantagem do Annotations é que você pode usar nas validações das telas.
    []s,
    Carlos.

  8. Jefferson says:

    Olá Carlos!

    Certa vez instalei o EF POCO no meu Visual Studio, e depois nunca mais consegui incluir um ADO.NET Model para usar a abordagem Designer, pois este item não aparecia mais no Visual Studio… Este problema ainda está ocorrendo?

    Grato, Jefferson.

  9. Stephan Spacov says:

    Apenas reforçarei o que todos disseram: Muito boa explicação!

  10. Carlos dos Santos says:

    Obrigado Jefferson!

  11. Fabiano Nalin says:

    Olá Carlos,

    Muito bom o conteúdo de seu blog, aprendi muito com os posts sobre o EF.

    Estou precisando migrar um sistema e decide tirar a camada de negócio do banco. Por conta disso estarei usando o Code First, no entanto, o banco já existe. Usando suas dicas usei o Power Tools para fazer a engenharia reversa.
    Eu achei o código muito poluído, algo parecido com que o EF4 usa no código do EDMX.

    Minha dúvida é, não teria como eu utilizar o simples mapeamento das entidades às classes, igualando os atributos com o banco e simplesmente indicar a base, sem a necessidade de utilizar o EF Power Tools?

    Abs.
    Fabiano

Leave a Reply

Anti-spam: complete the taskWordPress CAPTCHA


This blog is kept spam free by WP-SpamFree.