Engenharia Reversa no Entity Framework 5
Neste artigo irei abordar o uso da engenharia reversa num dos tópicos que vem crescendo muito para os desenvolvedores, o Entity Framework 5.
Neste artigo irei abordar o uso da engenharia reversa num dos tópicos que vem crescendo muito para os desenvolvedores, o Entity Framework 5. A evolução deste desde as primeiras versões é notável e atualmente o Entity Framework F 5 é público e open source, ou seja, você pode baixar do www.codeplex.com e melhorar a versão, caso precise.
O que é Engenharia Reversa no Entity Framework 5?
O Entity Framework é uma forma de abstrair uma fonte de dados de forma relacional, não importa qual seja a fonte, pois já há diversos (mais de 32) provedores de drives para o EF, por exemplo Oracle, mysql etc. Para explicar a resposta, veja a figura 1, onde temos diversos cenários para o EF 5. Caso não tenha um banco de dados e deseja escrever código da aplicação, use os cenários chamado de Novo Database (conforme a figura 1). Destacam-se o Model First – onde você define o modelo EDMX e gera o banco a partir deste – e o Code First – onde você cria as classes e o banco de dados é criado em tempo de execução. Se olharmos o segundo cenário de já termos um banco de dados, temos o Database First e o Code First. Ambos podem gerar um EDMX com as devidas classes automaticamente. No entanto, aqui é que entra a Engenharia Reversa, onde temos a possibilidade de não gerar o EDMX, e sim as classes de forma completamente separadas (graças aos templates T4 do VS.NET que já estão instalados). Isto nos permite trabalhar com as classes e o fantástico contexto (com o DbContext) sem ter um EDMX.

Por que usar Engenharia Reversa?
Em todos os tipos de projetos, e principalmente em times médios e grandes é comum ter o papel da pessoa que administra o banco de dados (DBA), onde toda e qualquer alteração deve passar sempre pelo crivo deste. Agora, o DBA, mais do que nunca, é o parceiro do desenvolvedor, pois o DBA pode validar uma nova estrutura (seja uma nova entidade, um novo tipo e tamanho de campo, etc) sem ter que colocar a mão no SQL, mysql, Oracle, etc. Ele apenas irá validar a estrutura na classe escrita em C# ou VB.NET e através do Migrations, o próprio desenvolvedor submeterá tais alterações. Para mais detalhes do Migrations, leia o artigo do Carlos dos Santos.
Agora, existem casos onde o próprio desenvolvedor faz tudo, desde o banco até a aplicação, então, fica tudo sob o domínio e o conhecimento dele. Particularmente gosto muito da Engenharia Reversa do EF 5 porque nos permite ter mais controle e produtividade no desenvolvimento, as classes e a estrutura do projeto ficam separadas, você consegue extender e customizar as classes.
O que preciso para usar a Engenharia Reversa?
Este tópico não vem instalado no Visual Studio .NET 2012 (também vale para o VS 2010), então, acesse o http://visualstudiogallery.msdn.microsoft.com/ e pesquise sobre “Entity Framework Power Tools”. É gratuito, basta fazer o download e instalar. Caso esteja com o VS aberto, é preciso reiniciá-lo.
Agora vamos criar um projeto, abra o VS 2012 e selecione New Project. Para mostrar tal funcionalidade, nada melhor que um projeto em C# do tipo Console Application. Dê o nome do projeto de EngReversaEF5, conforme a figura 2. Clique em OK para criar o projeto.

A primeira coisa a fazer é abrir o Solution Explorer, clicar com o botão direito no nome do projeto e selecionar Entity Framework / Reverse Engineer Code First, conforme a figura 3. Dica: caso a opção Entity Framework não aparecer é porque você não instalou o pacote citado anteriormente.

Será aberta uma janela solicitando qual é o banco de dados. No meu caso o servidor é EARTH e o banco é o famoso Northwind, conforme a figura 4. Obviamente você deverá selecionar o seu servidor e o respectivo banco de dados que queira aplicar a engenharia reversa.

Clique no botão OK e o VS se encarrega de criar e gerar todas as classes e o mapeamento, assim como o Contexto. Assim que finalizar, não se assuste com os erros porque neste projeto nós ainda não referenciamos o Entity framework 5. Eu fiz isto obrigatoriamente para você saber que é preciso referenciar o EF 5. Existem alguns tipos de projetos com ASP.NET MVC 4 que já faz a referência automaticamente, mas como este é de Console, faremos na mão.
Para isto, selecione o menu Tools / Library Package Manager / Manage NuGet Packages for Solution, pesquise sobre “entity framework 5”, conforme a figura 5. Assim que mostrar o pacote chamado EntityFramework, clique em Install e pronto, só alegria! Veja que a versão é a 5.0.0 e quando você instala qualquer pacote via NuGet, tenha certeza que terá a última versão e não precisa ficar pesquisando na internet onde está, qual versão usar, como instalar, quais referências fazer, etc, tudo isto é o NuGet que faz pra nós.

Nos bastidores, abra a pasta References e veja que foram referenciadas todas as classes, sendo a EntityFramework, System.Data.Entity e a System.ComponentModel.DataAnnotations.
Modelagem das classes
Abra a pasta Models (criada automaticamente com a Engenharia Reversa) e veja que temos todas as classes escritas em C# (.cs) de cada entidade e consultas do banco de dados Northwind.
Por exemplo, abra a classe Customer e veja como que foi gerada. Ela contém no construtor as referências com as quais ela se relaciona e a estrutura das propriedades em si.
C#
using System;
using System.Collections.Generic;
namespace EngReversaEF5.Models
{
public class Customer
{
public Customer()
{
this.Orders = new List<Order>();
this.CustomerDemographics = new List<CustomerDemographic>();
}
public string CustomerID { get; set; }
public string CompanyName { get; set; }
public string ContactName { get; set; }
public string ContactTitle { get; set; }
public string Address { get; set; }
public string City { get; set; }
public string Region { get; set; }
public string PostalCode { get; set; }
public string Country { get; set; }
public string Phone { get; set; }
public string Fax { get; set; }
public virtual ICollection<Order> Orders { get; set; }
public virtual ICollection<CustomerDemographic> CustomerDemographics { get; set; }
}
}
Agora vem o mais legal nesta parte de engenharia reversa. Na pasta Models/Mapping, abra o arquivo CustomerMap.cs. Veja que todo o mapeamento das propriedades estão escritos em FluentAPI, onde cada propriedade contém as devidas configurações, por exemplo, quem é a chave primária (HasKey), se é requerido (IsRequired), o tamanho máximo (HasMaxLenght), etc. Mais abaixo neste código você vê o mapeamento da entidade com a classe, ou seja, veja a seção chamada “Table & Column Mappings”, onde há a referência de qual entidade é no banco de dados (ToTable), assim como a propriedade (HasColumnName). Com isto você consegue criar um dicionário de dados, e isto vale para todas as classes geradas.
C#
using System.ComponentModel.DataAnnotations;
using System.Data.Entity.ModelConfiguration;
namespace EngReversaEF5.Models.Mapping
{
public class CustomerMap : EntityTypeConfiguration<Customer>
{
public CustomerMap()
{
// Primary Key
this.HasKey(t => t.CustomerID);
// Properties
this.Property(t => t.CustomerID)
.IsRequired()
.IsFixedLength()
.HasMaxLength(5);
this.Property(t => t.CompanyName)
.IsRequired()
.HasMaxLength(40);
this.Property(t => t.ContactName)
.HasMaxLength(30);
this.Property(t => t.ContactTitle)
.HasMaxLength(30);
this.Property(t => t.Address)
.HasMaxLength(60);
this.Property(t => t.City)
.HasMaxLength(15);
this.Property(t => t.Region)
.HasMaxLength(15);
this.Property(t => t.PostalCode)
.HasMaxLength(10);
this.Property(t => t.Country)
.HasMaxLength(15);
this.Property(t => t.Phone)
.HasMaxLength(24);
this.Property(t => t.Fax)
.HasMaxLength(24);
// Table & Column Mappings
this.ToTable("Customers");
this.Property(t => t.CustomerID).HasColumnName("CustomerID");
this.Property(t => t.CompanyName).HasColumnName("CompanyName");
this.Property(t => t.ContactName).HasColumnName("ContactName");
this.Property(t => t.ContactTitle).HasColumnName("ContactTitle");
this.Property(t => t.Address).HasColumnName("Address");
this.Property(t => t.City).HasColumnName("City");
this.Property(t => t.Region).HasColumnName("Region");
this.Property(t => t.PostalCode).HasColumnName("PostalCode");
this.Property(t => t.Country).HasColumnName("Country");
this.Property(t => t.Phone).HasColumnName("Phone");
this.Property(t => t.Fax).HasColumnName("Fax");
}
}
}
Até aqui já temos as classes e o mapeamento, mas onde é que está o contexto da classe? Na pasta Models localize e abra o arquivo NorthwindContext.cs. Logo na declaração da classe, veja que ela herda de DbContext, o qual é o responsável pelo gerenciamento do contexto, pelo rastreamento, pelo relacionamento das classes, ou seja, vale a pena selecionar o DbContext e pressionar F12 para ver a definição em detalhes.
No construtor da classe é feita a referência à chave que está no arquivo App.Config o qual define a conexão com o banco de dados, assim como o provider para o SQL Server, neste caso. Ou seja, se mudar qualquer detalhe da conexão, basta alterar o App.Config (se fosse um projeto de web seria Web.Config).
<connectionStrings>
<add name="NorthwindContext" connectionString="Data Source=EARTH;Initial Catalog=Northwind;Integrated Security=True;MultipleActiveResultSets=True" providerName="System.Data.SqlClient" />
</connectionStrings>
Em seguida são definidas as propriedades de cada entidade (agora classe .cs) referenciando o tipo DbSet, o qual é reponsável pelo CRUD, pesquisa, execução de instruções, etc de cada entidade. Na listagem a seguir eu omiti algumas classes devido ao tamanho do artigo, mas fique tranquilo que todas estarão listadas de acordo com o banco de dados.
C#
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using EngReversaEF5.Models.Mapping;
namespace EngReversaEF5.Models
{
public class NorthwindContext : DbContext
{
static NorthwindContext()
{
Database.SetInitializer<NorthwindContext>(null);
}
public NorthwindContext()
: base("Name=NorthwindContext")
{
}
public DbSet<Category> Categories { get; set; }
public DbSet<CustomerDemographic> CustomerDemographics { get; set; }
public DbSet<Customer> Customers { get; set; }
public DbSet<Employee> Employees { get; set; }
public DbSet<Product> Products { get; set; }
public DbSet<Region> Regions { get; set; }
public DbSet<Shipper> Shippers { get; set; }
public DbSet<Invoice> Invoices { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Configurations.Add(new CategoryMap());
modelBuilder.Configurations.Add(new CustomerDemographicMap());
modelBuilder.Configurations.Add(new CustomerMap());
modelBuilder.Configurations.Add(new EmployeeMap());
modelBuilder.Configurations.Add(new ProductMap());
modelBuilder.Configurations.Add(new RegionMap());
modelBuilder.Configurations.Add(new ShipperMap());
modelBuilder.Configurations.Add(new InvoiceMap());
}
}
}
Compilação do projeto
Chegou a tão esperada hora de compilar o projeto. O que sempre esperamos é Build com sucesso, nenhum erro, nem warning. Mas, neste caso, é preciso fazer alguns ajustes. Então, selecione o menu Build / Build Solution ou pressione F6. A lista de erros aparecerá informando (neste nosso caso do banco Northwind) que algumas classes (e já adianto que são referências as consultas que se tornaram classes) é preciso adicionar uma referência. Então, como exemplo, abra a classe RegionMap e note que o erro está no “DatabaseGeneratedOption”. O jeito mais rápido e fácil de corrigir isto é colocar o cursor sobre o “DatabaseGeneratedOption”, dar um CTRL + . (ponto) + ENTER para adicionar a referência a seguir na lista de using.
C#
using System.ComponentModel.DataAnnotations.Schema;
Consultas dados
Como já temos toda a estrutura de códigos pronta, vamos criar um código para listar todos os produtos. Abra o arquivo Program.cs e digite a seguinte listagem:
C#
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using EngReversaEF5.Models;
namespace EngReversaEF5
{
class Program
{
static void Main(string[] args)
{
using (NorthwindContext ctx = new NorthwindContext())
{
var produtos = ctx.Products.Where(p => p.UnitPrice <= 20)
.OrderBy(p => p.ProductName);
foreach (var item in produtos)
{
Console.WriteLine(string.Format("{0} - {1:c2} - estoque: {2:n0}",
item.ProductName, item.UnitPrice, item.UnitsInStock));
}
Console.ReadLine();
}
}
}
}
Veja que há a referência para “using EngReversaEF5.Models;” para se ter acesso ao contexto (NorthwindContext), seguido de uma expressão lambda para selecionar todos os produtos onde o preço seja menor ou igual a 20. Como se não bastasse, quero que os produtos sejam ordenardos (.OrderBy) pelo nome do produto (ProductName). Em seguida, é montado um looping foreach para listar algumas propriedades. Pressione F5 para executar o projeto e veja o resultado na Figura 6.

Em http://bit.ly/Nq798N você encontra mais detalhes sobre o Entity Framework 5, uso de engenharia reversa, uso do Migrations passo a passo. Faça um bom uso da engenharia reversa nos projetos, não deixe de experimentar as boas práticas do FluentAPI.








