Desenvolvimento - C#

Entity Framework 4

Utilizar o novo conceito Code First do Entity Framework 4.1 em uma aplicação ASP.NET MVC 3 com a view engine Razor.

por Israel Vilela



Quem acompanha a evolução do Entity Framework desde o início de sua vida conhece alguns problemas que o assombravam.  Apesar de  sua primeira versão ter sido relativamente bem aceita pela comunidade, ela não suportava algumas funcionalidades que todo ORM deve ter.

O principal problema da primeira versão do Entity Framework era o conceito chamado de Database First. Para resumir o cenário, era preciso primeiro ter toda a estrutura do banco de dados criada para podermos gerar nossas entidades no framework.

O problema  é que geralmente criamos diagramas de classes para identificar as entidades do domínio e seus relacionamentos, a partir daí sim criamos nosso banco de dados. Dessa forma era impossível trabalhar com Entity Framework pois o mesmo fazia uma “engenharia reversa” em nosso banco para criar as entidades.

Pensando nisso o time do Entity Framework veio com sua segunda versão ( que na verdade é a 4.0 ) que dentre as  novidades estava o conceito de Model First, que possibilitava ser criado um modelo com todas as entidades e a partir daí o banco era gerado.

Ainda não era o bastante, a comunidade ainda quería uma forma de criar suas classes de domínio deforma independente (chega de .edmx) e que pudessem “conversar” com o Entity Framework.

A partir daí surgiu a versão 4.1 que vêm como conceito “Code First”, onde podemos criar nossas classes e com algumas “anotações” dizer ao Entity Framework como elas serão mapeadas.  É esse modelo que iremos utilizar para desenvolver nosso projeto.

Antes de começar...

Segue os links para download dos recursos utilizados nesse artigo:

Criando o Projeto

Vamos começar criando uma aplicação ASP.NET MVC 3 com a linguagem C# como na figura abaixo:

Ao criar o projeto será apresentada uma tela para selecionarmos o tipo do projeto e a View Engine desejada. Selecione a opção Empty para criar um projeto vazio com apenas a estrutura básica de uma aplicação MVC.

Quanto a View Engine selecione Razor para utilizar a nova forma de programar a apresentação (view) de sua aplicação.

Com o projeto criado vamos começar a trabalhar com nossas entidades, nosso objetivo será criar uma classe de Produtos e outra de Categorias com os atributos necessários para que o Entity Framework consiga criar as tabelas como no modelo abaixo:

Criando as entidades

 

Para começar, adicione uma classe Produto na pasta Model do projeto conforme abaixo:

    [Table("tbProduto")]

    public class Produto

    {

        public int id { get; set; }

        [StringLength(100)]

        public string nome { get; set; }       

     

        [Column(TypeName="Money")]

        public decimal preco { get; set; }

        [Column("QTD")]

        public int quantidade { get; set; }      

       

        public virtual Categoria Categoria { get; set; }        

    }

Entendendo o código:

Na classe adicionamos um atributo para informar que o nome da tabela referente a entidade produto será tbProduto.  As outras anotações informam que a coluna nome terá um tamanho de 100 caracteres, a coluna preço será do tipo Money e a coluna quantidade terá o nome de QTD.

Note que adicionamos uma propriedade virtual, o Entity Framework irá utilizar essa propriedade para criar uma chave estrangeira e fazer a navegação com a Categoria do produto.

Também deve ser observado que toda propriedade com nome “id” será mapeada como chave primária (PK) da tabela.

Lembre-se de adicionar uma  referência ao namespace System.ComponentModel.DataAnnotations. Ele permite utilizar os atributos em nossa classe que servirão como instruções para o Entity Framework.

Vamos para a entidade Categoria:

    [Table("tbCategoria")]

    public class Categoria

    {

        public int id { get; set; }

        public string nome { get; set; }

        public virtual ICollection<Produto> Produtos { get; set; }

    }

Adicionamos nessa classe uma propridade virtual do tipo ICollection indicando que uma categoria pode ter muitos produtos ( 1 * N ).

Criando o Contexto

Com nossas entidades criadas precisamos criar nosso Contexto, é ele que irá agrupar nossas entidades e permitir trabalhar com as mesmas.

Adicione uma classe em Model como o modelo a seguir:

public class Contexto : DbContext

{

public Contexto()

: base("strConn")

{ }

public DbSet<Produto> Produtos { get; set; }

public DbSet<Categoria> Categorias { get; set; }

}

Toda classe que irá funcionar como um Contexto deve herdar de DbContext, note que criamos um construtor que chama o construtor da classe base passando a string “strConn” que nada mais é que o nome da string de conexão a ser utilizada.

Também adicionamos propriedades do tipo DbSet que representam coleções de todas as entidades do Contexto, resumindo para cada entidade teremos um DbSet.

Antes de continuar adicione no arquivo Web.config uma string de conexão como o modelo abaixo:

<connectionStrings>

<add name="strConn" connectionString="Data Source=servidor;Initial Catalog=banco de dados;Persist Security Info=True;User ID=usuario;Password=senha;" providerName="System.Data.SqlClient" />

</connectionStrings>

Criando o Inicializador

No Code First podemos criar uma classe que cria o banco de dados conforme o nosso contexto caso o banco ainda não exista, e ainda inserir alguns registros iniciais.

Para isso devemos criar uma classe que implementa IDatabaseInitializer:

    public class Inicializador : IDatabaseInitializer<Contexto>

    {

        public bool _deletar;

        public Inicializador(bool deletarBD)

        {

            _deletar = deletarBD;

        }

        public void InitializeDatabase(Contexto context)

        {

            if (_deletar)

            {

                context.Database.Delete();

                context.Database.CreateIfNotExists();

                var catLivros = new Categoria();

                catLivros.nome = "Livros";

                context.Categorias.Add(catLivros);

                var Produto1 = new Produto();

                Produto1.nome = "Harry Potter";

                Produto1.preco = 29.90m;

                Produto1.quantidade = 200;

                Produto1.Categoria = catLivros;

                var Produto2 = new Produto();

                Produto2.nome = "As Crônicas de Gelo e Fogo";

                Produto2.preco = 49.90m;

                Produto2.quantidade = 300;

                Produto2.Categoria = catLivros;

                context.Produtos.Add(Produto1);

                context.Produtos.Add(Produto2);

                context.SaveChanges();

            }

        }

    }

Como podemos notar, a classe Inicializador têm um construtor que recebe um valor do tipo booleano, se o mesmo for true o banco de dados é deletado e recriado e alguns registros são adicionados.

Vamos instanciar nossa classe no evento Application_Start encontrado no arquivo Global.asax:

        protected void Application_Start()

        {

            AreaRegistration.RegisterAllAreas();

            RegisterGlobalFilters(GlobalFilters.Filters);

            RegisterRoutes(RouteTable.Routes);

            //Inicializa o Banco de Dados

            Database.SetInitializer(new Inicializador(true));

        }

 

Com tudo pronto vamos partir para os Controllers e Views de nossa aplicação:

Adicione um controle ProdutosController como o modelo abaixo:

    public class ProdutosController : Controller

    {

        public ActionResult Index()

        {

            ViewData.Model = (new Contexto()).Categorias.ToList();

            return View();

        }

        public ActionResult Categoria(string id)

        {

            int categoriaId = Convert.ToInt16(id);

            ViewData.Model = (new Contexto()).Produtos.Where(p => p.Categoria.id == categoriaId);

            return View("Listar");

        }

    }

Note que temos duas Actions, uma para listar as categorias de produtos caso o endereço seja /produtos e outro para listar todos os produtos de uma determinada categoria caso o endereço digitado seja /produtos/categoria/codigo.

Clique com o botão direito na action Index e em Add View, a seguinte tela será apresentada:

Iremos criar uma view fortemente tipada para mostrar todas as categorias, note que a View Engine Razor utiliza arquivos na extenção CSHTML.

A View Index terá o seguinte código:

@model IEnumerable<Models.Categoria>

             

@using Models;

@{

    ViewBag.Title = "Exemplo: EF 4.1 Code First com MVC 3 Razor";   

}

<h2>

    Categoria de Produtos</h2>

<ul>

@foreach (Categoria categoria in Model)

{

    <li>

        <a href="/produtos/categoria/@categoria.id">@categoria.nome</a>

    </li>

}

</ul>

Como podemor perceber o código da apresentação fica muito mais limpo utilizando a sintaxe do Razor, note que ele é esperto o bastante para saber quando começa o HTML, sem precisarmos ficar abrindo e fechando tags como acontecia com a engine do ASPX.

Vamos adicionar mais uma View chamada Listar, responsagem por mostrar todos os produtos de uma determinada categoria:

@model IEnumerable<Models.Produto>

             

@using mvc3_ef41.Models;

@{

    ViewBag.Title = "Exemplo: EF 4.1 Code First com MVC 3 Razor";   

}

<h2>

    Produtos</h2>

<ul>

@foreach (Produto produto in Model)

{

    <li>

        @produto.nome

    </li>

}

</ul>

Testando a aplicação

Já está tudo pronto para testar nossa aplicação, ao testar pela primeira vez o Entity irá criar o banco e as tabelas referentes as nossas entidade como ilustrado abaixo:

Reparem que além de uma tabela para cada entidade também foi criada uma tabela chamada EdmMetadata. Essa tabela guarda o esquema do modelo atual das nossas entidades e permite que seja detectado alguma alteração para o banco ser recriado.

Acessando o endereço /produtos teremos o seguinte resultado:

Clicando na categoria é apresentado todos os produtos da mesma:

Lembre-se que depois do primeiro teste, deve ser alterado o valor passado para seu Inicializador para false, dessa forma o Entity Framework não irá excluir e criar novamente seu banco de dados.

Conclusão

O recurso Code First do Entity Framework mostra-se recomendado para quem estava preso ao Model Designer das versões anteriores. Tudo isso aliado com a ótima Razor View Engine do MVC  tornam o EF 4.1 + MVC 3 uma ótima receita para desenvolvimento.

Israel Vilela

Israel Vilela