Back-End

4 abr, 2012

Como fazer um mapeamento com Entity Framework Code First

Publicidade

O Entity Framework é um projeto de mapeamento de banco de dados relacionais da Microsoft, desenvolvido pela equipe responsável pelo ADO.NET. Uma ORM (mapeamento de objeto relacional, como NHibernate, SubSonic, ActiveRecord) que tem crescido muito em adoção, principalmente em novos projetos utilizando ASP.NET.

O Code First é uma tecnologia recentemente incorporada ao EF, possibilitando gerar os objetos de negocio sem pensar no banco de dados e na forma como serão armazenados. A partir de padrões e convenções que seguem o que já é de praxe no desenvolvimento com .NET, o desenvolvedor define os objetos e seus comportamentos, depois configura o mapeamento de forma desacoplada, sem impactar nos objetos já definidos.

Embora o CF tenha sido pensado para que a base de dados seja criada a partir dos modelos (objetos), é fácil utilizá-lo sobre uma base legada, que não segue os padrões e convenções definidas para o CF. Mas nesse caso, qual é a vantagem te utilizar o CF e não os modelos convencionais do EF (famoso edmx)? O CF permite um controle mais apurado dos objetos, e remove a dependência do gerador visual dos modelos. Mas isso é assunto para um próximo artigo.

Hoje vamos fazer, passo a passo, um mapeamento com Code First.

Pense no negócio!

O primeiro passo é esquecer que existe EF, CF e até banco de dados. Se desapegue disso – pelo menos por enquanto. Pense no negócio, no que sua aplicação deve fazer e crie os objetos.

Para o exemplo vamos criar algo bem simples: uma exclusiva, única e jamais utilizada engine de blog. Primeiramente, vou imaginar o que meu blog vai ter: artigo, autor e tags… Muito inovador! Agora é criar os objetos.

public class Artigo
{
public Artigo()
{
Tags = new List<Tag>();
}

public int Id { get; set; }

public string Title { get; set; }

public string Text { get; set; }

public Autor Autor { get; set; }

public IList<Tag> Tags { get; set; }
}

public class Autor
{
public int Id { get; set; }

public string Name { get; set; }
}

public class Tag
{
public int Id { get; set; }

public string Title { get; set; }
}

Perceba que as as classes não possuem referência alguma para o Entity Framework; são objetos normais. Inclusive, essa é a intenção: desacoplar a lógica de acesso a banco de dados dos objetos de negócio.

Baixando as referências

Há duas formas de fazer isso. Ou baixe os binários do Entity Framework (versão 4.1), ou utilize o NuGet (que você já deveria conhecer) com o comando Install-Package EntityFramework. Se você baixou os binários, não esqueça de adicionar os Assemblies nas referências do projeto; se usou o NuGet, isso já foi feito por ele.

DatabaseContext

Agora sim começamos a pensar no banco de dados, criando um objeto chamado DatabaseContext, que vai fazer todo trabalho sujo. Esse objeto deve herdar DbContext, que é do Entity Framework (namespace System.Data.Entity).

Vale lembrar que é extremamente recomendável separar esse objeto das classes de negócio. Deixe-os em projetos diferentes, evitando acoplamento e facilitando a manutenção. O projeto de negócio não conhece banco de dados; ele nem deve saber que vai ser persistido.

public class DatabaseContext : DbContext
{
public DbSet<Artigo> Artigos { get; set; }

public DbSet<Tag> Tags { get; set; }

public DbSet<Autor> Autores { get; set; }
}

O BbSet é um objeto do EF que representa uma tabela, ou mais ou menos isso; então, cada objeto que vai ser persistido no banco deve ser mapeado.

Criando o banco de dados (CREATE)

Primeiro, é necessário inserir (no arquivo de configuração da aplicação) uma ConnectionString com o mesmo name do objeto DbContext, que nesse caso é DatabaseContext. Essa configuração vincula o objeto ao banco de dados.

Notem que no meu caso vou utilizar o provider System.Data.SqlClient, que é do SQL Server. O EF já possui suporte a outros bancos de dados, como Oracle (que possui projeto oficial em fase beta) e MySQL, mas esse também é um assunto para outro artigo.

<connectionStrings>
<add name="DatabaseContext" connectionString="[INSIRA_SUA_CONNECTION_STRING]" providerName="System.Data.SqlClient" />
</connectionStrings>

Agora, para criar o banco de dados, rode o seguinte comando:

using (var dataContext = new DatabaseContext())
{
dataContext.Database.Create();
}

Preste atenção na forma de usar o DatabaseContext. Ele deve ser utilizado com o using, pois esse se encarrega de fechar os recursos alocados pelo acesso a banco, como a famosa connection. Se, por algum motivo muito estranho, não for possível utilizar o using, feche os recursos utilizando o método Dispose do DatabaseContext.

Inserindo dados (INSERT)

Agora vamos manipular os primeiros dados utilizando EF. Como sempre, precisamos do objeto DatabaseContext – lembre-se que ele é sua porta de entrada para o banco de dados.

var autor = new Autor { Name = "Wagner Andrade" };

var artigo = new Artigo
{
Autor = autor,
Title = "Entity Framework",
Text = "Uma forma simples e limpa de acessar os dados relacionais."
};

artigo.Tags.Add(new Tag { Title = ".NET" });
artigo.Tags.Add(new Tag { Title = "Desenvolvimento" });
artigo.Tags.Add(new Tag { Title = "ADO.NET" });
artigo.Tags.Add(new Tag { Title = "Entity Framework" });

using (var dataContext = new DatabaseContext())
{
dataContext.Artigos.Add(artigo);
dataContext.SaveChanges();
}

Primeiramente, criei a estrutura de objetos que representa um artigo, com seu autor e tags. Depois abri o contexto de acesso ao banco de dados, adicionei o novo artigo e, por fim, o método SaveChanges do contexto. Esse método é o que faz a coisa acontecer de verdade. Até ele nada foi manipulado a nível de banco de dados. Lembra do commit? Pois então, é uma analogia perfeita.

Buscando dados (SELECT)

Acessar dados no banco é tão fácil quanto persistí-los.

using (var dataContext = new DatabaseContext())
{
var artigo = dataContext.Artigos.Find(1);
}

Nesse caso, utilizei o Find para buscar no banco o artigo com PrimaryKey 1, nesse caso, segundo as convenções do EF (PrimaryKey padrão é a property Id), artigo com Id == 1.

O artigo encontrado retorna sem suas tags (lista Tags == null), pois essas estão em outra tabela no banco de dados, e é necessário fazer um Join para buscá-las. Porém, fazer Join entre as tabelas também é trivial e transparente. Basta utilizar o EF. Na verdade, nem deve ser encarado como um Join (porque esse conceito não existe na programação orientada a objetos), mas sim como o carregamento de uma lista dentro de um objeto.

using (var dataContext = new DatabaseContext())
{
var artigo = dataContext.Artigos
.Include(a => a.Tags)
.First(a => a.Title.Contains("Entity"));
}

O método Include está informando que as tags devem ser incluídas, através de um Join, na query que vai buscar o artigo no banco. Mas na prática, o Include deve ser utilizado para buscar as listas do objeto. Para utilizar tal método, é necessário incluir (using) o namespace System.Data.Entity.

Mas porque isso não é feito automaticamente? Porque, na maioria dos casos, um objeto tem muitas dependências e elas também possuem outras. Ou seja, uma simples busca de um objeto poderia ocasionar um query gigantesca, carregando todas as dependências recursivamente.

Alterando e removendo dados (UPDATE e DELETE)

Esse talvez seja o processo mais facilitado pelo EF, se já não bastasse todo tempo que ele nos poupou até agora.

// Alterar.
using (var dataContext = new DatabaseContext())
{
var artigo = dataContext.Artigos.Find(1);
artigo.Title = "EF";
dataContext.SaveChanges();
}

// Remover.
using (var dataContext = new DatabaseContext())
{
var artigo = dataContext.Artigos.Find(1);
dataContext.Artigos.Remove(artigo);
dataContext.SaveChanges();
}

É simples assim! Primeiro busquei no contexto o artigo que quero modificar, depois alterei o titulo e SaveChanges. Pronto, atualizado no banco.

Para remover foi tão fácil quanto. Primeiro busquei o mesmo artigo, removi da lista de artigos do contexto e SaveChanges.

Esse artigo, obviamente, aborda um passo a passo bem básico sobre o Entity Framework Code First. Existem muitos assuntos a serem tratados, mas espero que isso sirva de porta de entrada para uma tecnologia tão promissora.