Seções iMasters
.NET + C# + Visual Studio

Entity Framework 4 – Usando POCO, Code First e as convenções padrão

Está prevista, ainda para o
primeiro semestre deste ano, uma nova versão do Entity Framework
4, com o objetivo de tornar a ferramenta cada
vez melhor.

Enquanto a versão final não sai, vamos falar um pouco sobre uma das suas últimas atualizações, a Entity Framework Feature Community Technology Preview – CTP5, mais precisamente da funcionalidade Code-First e POCO.

Obs: Para baixar a versão CTP5 aqui: http://tinyurl.com/5rg52tg

Nota: A
versão anterior, a CTP4, já permitia usar o recurso do
First-Code com um banco de dados existente mas exigia mais
intervenção do desenvolvedor com a CTP5 tudo ficou mais
simples.

O Entity Framework é uma ferramenta
OR/M que realiza o mapeamento objeto relacional gerando entidades
e mapeando-as para as tabelas do banco de dados.. Em sua primeira versão, praticamente não havia o que é conhecido como Code-First(Código Primeiro), ou seja, a possibilidade de
gerar o modelo de negócios e suas entidades sem ter que primeiro
criar o banco de dados.

Para quem trabalha usando o
paradigma da orientação a objetos deveria ser natural iniciar o
desenvolvimento pelo modelo de entidades, onde as classes são
definidas para representar o domínio do negócio.
Posteriormente, e a partir destas classes, seria gerado o banco
de dados usado pela aplicação para realizar a persistência das
informações. Deveria ser assim, mas a primeira
versão do EF não permitia esse recurso.

Tentando contornar este problema
eram feitos certos malabarismos, mas ainda assim, havia
uma dependência muito forte do mapeamento gerado pelo EF4 através
do Entity Data Model, o que incomodava muita
gente. Até que a Microsoft liberou atualizações que permitem maior independência do Framework, através da
criação de classes POCO (Plain Old CLR Objects) que não herdam das classes base
geradas pelo EF.

Quando decidimos usar o Code-First
não precisamos começar nossa aplicação criando o banco de
dados ou definindo um esquema mas podemos iniciar escrevendo
classes .NET para definir o modelo de objetos do nosso domínio
sem ter que misturar a lógica de persistência de dados com as
classes.

O Entity Framework, por padrão, adota
algumas convenções (Conventions) que ele usa
para realizar algumas operações.

Mas o que são essas convenções?

Consultando o dicionário teremos a
seguinte definição: Acordo, pacto,
contrato: convenção verbal , aquilo que está geralmente
admitido ou tacitamente contratado.

Em nosso contexto, podemos dizer que
uma convenção é uma regra padrão pelo qual não teremos que
fazer algumas configurações de mapeamento para nossas
entidades, sendo que o EF4 vai , baseado nessas convenções,
realizar as tarefas de forma automática.

Na CTP5 , as convenções estão
definidas por uma hierarquia de subclasses que implementam um
contrato comum chamado IConvention. Uma simples
definição deste contrato pode ser visto no código abaixo:

C#

public interface IConvention
{
}

VB .NET

Public Interface IConvention
End Interface

Debaixo de IConvention
temos elementos como AttributeConfigurationConvention,
IDbConvention e IEdmConvention que nos interessam mais,
uma vez que eles representam os contratos através dos quais
foram implementadas as diversas convenções.

Antes de entrarmos em detalhes sobre as Convenções, criaremos um exemplo no EF4, para mostrar como ele se comporta
usando as convenções padrão, para entendermos o seu
comportamento e assim alterá-lo se assim desejarmos.

CTP5
– Usando POCO com as convenções padrão

Se usarmos o EF para realizar o
mapeamento criando o Entity Data Model teremos
uma grande ajuda da ferramenta, mas em muitos casos isso ao invés
de ajudar acabará atrapalhando, pois o código verboso gerado pode
ser um problema para integrar com o nosso modelo ou mesmo
transmitir usando Web Services.

Vamos então mostrar como usar POCO
sem criar o Entity Data Model e também usar o Code-First
gerando o banco de dados e as tabelas a partir de nossas
entidades.

Mas o que são essas classes POCO?

POCO – Plain Old CLR Object – são classes simples de domínio que possuem apenas get/sets e um construtor e que não dependem de nenhum framework; as classes POCO não são obrigadas a herdar de nenhuma outra classe ou implementar nenhuma interface.Portanto as classes POCO  são independente de frameworks.

Vamos iniciar criando o nosso modelo
de negócio através da definição das classes do nosso
domínio. Para tornar a tarefa mais suave e de fácil
entendimento adotaremos um modelo simplificado que pode ser visto
no diagram de classes a seguir:

A cardinalidade é um
conceito importante para ajudar a definir o relacionamento, ela
define o número de ocorrências em um relacionamento. Para
determinar a cardinalidade, deve-se fazer a pergunta relativa ao
relacionamento em ambas as direções. No exemplo a seguir, temos

  • Um
    Curso possui quantos alunos?  R: no mínimo 1 e no
    máximo N;
  • Um
    aluno está alocado em quantos cursos? R- no mínimo em 1
    e no máximo em 1;

Para implementar o nosso exemplo, usaremos o Visual
Basic 2010 Express Edition e
criando um novo projeto chamado EF4_Poco_Escola
via menu File->New Project escolhendo o
template Windows Forms Application;

Obs: Você
vai precisar ter instalado o SQL Server 2005 ou 2008 Express
Edition.

No menu Project
clique em Add Reference. Selecione a guia Browse e localize a
dll EntityFramework na pasta onde foi instalada
a CTP5 (c:Arquivos Programas)

Os recursos da EF Code First
CTP5
tem um nome de assembly atualizado e novo
namespace .NET:

  • Nome do Assembly: EntityFramework.dll
  • Namespace:
    System.Data.Entity

No formulário form1.vb vamos
definir uma interface bem simples apenas para exibir as mensagens
durante a execução do código. Inclua um controle ListBox (lstResultado)
e um botão de comando (btnExecutar) conforme o layout
da figura abaixo:

Definindo
as classes de negócio

Vamos definir as classes Curso e
Aluno no projeto da seguinte forma:

1 – No menu Project selecione Add
Class e informe o nome Modelo.vb e
clique no botão Add.

A seguir defina as classes Curso
e Aluno
no arquivo Modelo.vb conforme o
código abaixo:

Public Class Curso

Private m_CursoId As Integer
Public Property CursoId() As Integer
Get
Return m_CursoId
End Get
Set(ByVal value As Integer)
m_CursoId = valu
End Set
End Property

Private m_nome As String
Public Property Nome() As String
Get
Return m_nome
End Get
Set(ByVal value As String)
m_nome = value
End Set
End Property

Private m_escolaid As Integer
Public Property EscolaId() As Integer
Get
Return m_escolaid
End Get
Set(ByVal value As Integer)
m_escolaid = value
End Set
End Property

Public Property Alunos() As ICollection(Of Aluno)
Get
Return m_Alunos
End Get
Set(ByVal value As ICollection(Of Aluno))
m_Alunos = value
End Set
End Property
Private m_Alunos As ICollection(Of Aluno)
End Class

Public Class Aluno

Private m_AlunoId As Integer
Public Property AlunoId() As Integer
Get
Return m_AlunoId
End Get
Set(ByVal value As Integer)
m_AlunoId = value
End Set
End Property

Private m_nome As String
Public Property Nome() As String
Get
Return m_nome
End Get
Set(ByVal value As String)
m_nome = value
End Set
End Property

Private m_Email As String
Public Property Email() As String
Get
Return m_Email
End Get
Set(ByVal value As String)
m_Email = value
End Set
End Property

Public Property Curso() As Curso
Get
Return m_curso
End Get
Set(ByVal value As Curso)
m_curso = value
End Set
End Property
Private m_curso As Curso

End Class

2 – No menu Project
selecione Add Class e informe o nome AcessoDados.vb
e clique no botão Add.

Vamos definir a classe AcessoDados
que herda de DbContext e utilizar:

Imports System.Data.Entity

Public Class AcessoDados

Public Class ContextoCurso
Inherits DbContext

Private m_Cursos As DbSet(Of Curso)
Public Property Cursos() As DbSet(Of Curso)
Get
Return m_Cursos
End Get
Set(ByVal value As DbSet(Of Curso))
m_Cursos = value
End Set
End Property

Private m_Alunos As DbSet(Of Aluno)
Public Property Alunos() As DbSet(Of Aluno)
Get
Return m_Alunos
End Get
Set(ByVal value As DbSet(Of Aluno))
m_Alunos = value
End Set
End Property
End Class

End Class

Um dos aprimoramentos digno
de nota é que o CTP5 é uma versão simples das duas
classes:

ObjectContext permite consultar,
controle de alterações e salvar no banco de dados.
ObjectSet encapsula os conjuntos de
objetos semelhantes.

O
DbContext é um invólucro para ObjectContext
e além disso esta classe contém:

- Um conjunto de APIs que
são mais fáceis de usar do que a exposta pelo ObjectContext;
– As APIs que permitem utilizar o recurso do Code-First e
as convenções;

O DbSet é
um invólucro para ObjectSet.

Definindo o código para executar a
criação das tabelas do banco de dados e a persistência dos
dados. Vamos agora definir o código no
formulário form1.vb no evento Click
do botão de comando vamos chamar a rotina geraTabelasBD:

Private Sub btnExecutar_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnExecutar.Click
geraTabelasBD()
End Sub

O código da rotina geraTabelasBD
é visto a seguir:


Private Sub geraTabelaBD()

lstResultado.Items.Clear()
lstResultado.Items.Add("Gerando as tabelas e o banco de dados")
Using contextoCurso As New ContextoCurso()

Dim curso As New Curso() With {
.Nome = "Entity Framework",
.EscolaId = 100
}

lstResultado.Items.Add("")
lstResultado.Items.Add("Entidade Curso criada com sucesso: nome='Entity Framework', Escolaid=100")

contextoCurso.Cursos.Add(curso)

lstResultado.Items.Add("")
lstResultado.Items.Add("O curso foi incluído na coleção Cursos")

Dim macoratti As New Aluno() With
{
.Nome = "Jose Carlos Macoratti",
.Curso = curso,
.Email = "macoratti@yahoo.com"
}

lstResultado.Items.Add("")
lstResultado.Items.Add("Entidade Aluno criada com sucesso: nome='Jose Carlos Macoratti'")

contextoCurso.Alunos.Add(macoratti)

lstResultado.Items.Add("O aluno foi incluído na coleção Alunos")

Dim registros As Integer = contextoCurso.SaveChanges()

lstResultado.Items.Add("As entidades foram persistidas")
lstResultado.Items.Add("")
lstResultado.Items.Add("Registros afetados :" + registros.ToString())

End Using
End Sub

Executando o projeto e clicando no
botão iremos obter o seguinte resultado:

Feito isso, vamos verificar como o
Entity Framework se comportou e quais as operações que ele
realizou. Agora vamos dar uma olhada no SQL Server
instalado na máquina local através do SQL Server
Management Studio.

Na figura abaixo vemos que o banco
de dados EF4_Poco_Escola.AcessoDados+ContextoCurso
foi criado. Foram criadas também as tabelas Alunos
e Cursos e também foram persistidas os dados conforme
mostra a figura a seguir:

Obs: O
nome das tabelas geradas foram Alunoes e Cursoes. O EF4 aplicou
uma convenção baseada na gramática inglesa que cria a tabela
com o nome da classe no plural.(*)

O conteúdo as
tabelas Cursos e Alunos exibindo os dados incluídos:

Partindo das nossas classes POCO,
o EF4 – CTP5 realizou todo o trabalho de criação do
banco de dados e das tabelas e também da persistência das
informações.

Resumindo o que o EF4 fez:

  • Se conectou a
    uma instãncia do SQL Server na máquina local (.SQLEXPRESS)
    usando a autenticação do Windows;
  • Verificou a
    existência do banco de dados com o nome qualificado da
    classe que herda de DbContext;
  • Descobriu as
    propriedades das classes Aluno e Curso;
  • Inferiu a
    existência do relacionamento um-para-muitos entre
    a classe Curso e a classe Aluno;
  • Criou as
    tabelas Alunos e Cursos com os tipos e
    os relacionamentos pertinentes;
  • Inclui os dados
    em cada uma das tabelas executando o comando SaveChanges();

Caramba! Como ele sabe fazer tudo
isso sozinho?

Elementar meu caro, ele usa as
convenções pré-definidas.

E quais seriam então essas
convenções?

Segue um resumo :

  1. Se você não definir um
    endereço para o servidor , o EF4 CTP5 irá tentar
    realizar uma conexão local;
  2. O nome da tabela criada será o
    nome da classe no plural (usando a sintaxe da
    gramática da língua Inglesa.No exemplo: Alunoes
    e Cursoes);
  3. Se não for definido um nome
    para o banco de dados , ele será criado com o nome do
    projeto mais o nome da classe do contexto;
  4. Se uma classe tem uma
    propriedade de navegação para outra classe e esta
    possuir uma coleção da primeira, o EF infere que existe
    um relacionamento do tipo um-para-muitos entre as
    classes;
  5. Se existe uma propriedade com
    nome igual ao nome da classe mas termina em Id (‘nomeClasse’+Id)
    ou se o nome da propriedade é apenas Id esta propriedade
    será a chave primária;
  6. Se a chave primária é do tipo
    inteiro ele é do tipo Identity;

Você pode alterar as convenções
padrão definindo suas próprias convenções e assim ter um
maior controle sobre as tarefas realizadas mas isso é um assunto
para outro artigo.

Pegue o projeto completo em:  EF4_Poco_Escola.zip (versão VB .NET) e EF4_Poco_Conventions.zip (Versão C#)

Eu sei é apenas EF, mas eu
gosto…

Comente também

2 Comentários

Cesar Vilarim

O código apresentado no artigo (e mesmo o que está para download) não funciona.
Faltaram dois detalhes básicos:

1º – É necessário indicar a string de conexão normalmente;
2º – É necessário passar a conexão ao contexto logo após ele ser instanciado. Ex.:
contextoCurso.Database.Connection.ConnectionString =
ConfigurationManager.ConnectionStrings[“SqlConnection”].ToString();

Espero ter ajudado.

André

terceiro artigo que leio em vb.net. Faz em C#, ninguem usa essa linguagem fora os dinossauros.

Qual a sua opinião?