Entity Framework 4.1 - ASP .NET com Code-First (C#) - I
Em artigos anteriores eu já apresentei os novos recursos do Entity Framework 4.1 como Code-First, os recursos da nova API DbContext, as convenções padrão, os Data Annotations, etc. |
Neste artigo vou criar uma aplicação ASP .NET usando grande parte dos recursos
disponíveis no Entity Framework 4.1 para mostrar como usá-los em uma aplicação
real.
Recursos usados
Eu vou usar os seguintes recursos:
Obs: Você deve ter o SQL Server 2008 Express Edition instalado
Objetivos
Criar uma aplicação ASP .NET e realizar as operações CRUD usando os recursos do Entity Framework 4.1 (Code-First, API DBcontext, Data Annotations, Validações, Mapeamentos, etc.)
Criando a aplicação ASP .NET
Abra o Visual Web Developer 2010 Express Edition (a versão é gratuita) e no menu File selecione New Project;
Selecione a linguagem C# (note que você também pode escolher Visual Basic) , clique em Web e a seguir escolha o template: ASP .NET Empty Web Application
Informe o nome Escola_CRUD_EF41 e clique em OK; (observe a localização do seu projeto e o nome da solução)
Será criado um projeto vazio.
Neste exemplo eu não vou criar outros projetos na solução vou trabalhar apenas com uma solução e um projeto.
Como vamos usar os tipos a partir do EF 4.1 precisamos incluir uma referência ao assembly EntityFramework;
No menu Project selecione Add Reference e a seguir selecione a guia Browse e localize a pasta onde você instalou o Entity Framework 4.1;
A seguir selecione o assembly EntityFramework.dll e clique no botão OK;
Precisamos também incluir uma referência ao assembly do Entity Framework existente.
Repita o processo acima e selecione a guia NET e seguir procure pelo assembly System.Data.Entity selecione-o e clique em OK;
Precisamos também incluir uma referência a System.ComponentModel.DataAnnotattions;
Repita o processo acima e selecione a guia NET e seguir procure pelo assembly System.ComponentModel.DataAnnotattions selecione-o e clique em OK;
Pronto as referências já estão todas adicionadas ao projeto.
Definindo o modelo
Vamos definir um modelo muito simples usando classes. Como estamos iniciando eu vou criar classes separadas no mesmo projeto mas o mais correto seria criar um projeto separado e nele criar as classes. Vou criar uma pasta chamada Model no projeto, e nela criar as nossas classes.
Obs: Vou usar praticamente o mesmo modelo do artigo : Entity Frameweork 4 - Usando Data Annotations (VB .NET)
Clique com o botão direito sobre o nome do projeto e selecione Add -> New Folder e a seguir informe o nome: Model
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 vou adotar um modelo simplificado que pode ser visto no diagrama de classes a seguir:
Esta modelagem não esta essencialmente
correta, esta sendo usada apenas por questão didática.
|
O nosso modelo
de negócio consiste de das classes:
O modelo de classes representa um Curso
que possui 1 ou mais alunos, e um professor que ministra um ou mais cursos. Temos aqui uma associação que representa o
relacionamento um-para-muitos. |
A seguir com o modelo em mente vamos criar cada classe que representa as entidades acima descritas.
Clique com o botão direito do mouse sobre a pasta Model e selecione Add Class e a seguir informe o nome Aluno.cs e clique no botão Add;
A seguir defina o seguinte código para a classe Aluno:
using System.ComponentModel.DataAnnotations;namespace Escola_CRUD_EF41.Model{ [ Table("Aluno")]public class Aluno { [ Key][ DatabaseGenerated(DatabaseGeneratedOption.Identity)]public int alunoCodigo { get; set; } [ StringLength(50)][ Required(ErrorMessage="O nome do aluno é obrigatório")]public string alunoNome { get; set; } [ StringLength(80)][ Required(ErrorMessage = "O email do aluno é obrigatório")]public string alunoEmail { get; set; } [ Required , StringLength(1, ErrorMessage = "Informe apenas M ou F")]public string alunoSexo { get; set; } [ Required]public int cursoCodigo { get; set; }
public virtual Curso Curso { get; set; } } } |
Data Annotations usados na definição
da classe Aluno: A Annotation [Table("Aluno")] define o nome da tabela que será gerada; A Annotation [DatabaseGenerated(DatabaseGeneratedOption.Identity)] A Annotation [StringLength(50)] define que o campo string alunoNome terá um tamanho de 50 caracteres; A Annotation [Required(ErrorMessage="O nome do aluno é obrigatório")] define que o campo alunoNome é obrigatório;A Annotation [Required , StringLength(1, ErrorMessage = "Informe apenas M ou F")] define uma restrição para o campo alunoSexo. A Annotation [ForeignKey("cursoCodigo")] informa que o atributo será a chave estrangeira da tabela Aluno; |
Repita o processo acima e cria a classe Curso definindo nesta classe o código abaixo:
using System.ComponentModel.DataAnnotations;using System.Collections.Generic;namespace Escola_CRUD_EF41.Model{
[ Table("Curso")]public class Curso { [ Key][DatabaseGenerated(DatabaseGeneratedOption.Identity)] public int cursoCodigo { get; set; }
[Required(ErrorMessage = "O nome do curso é obrigatório")] public string cursoNome { get; set; } public virtual ICollection<Aluno> Alunos { get; set; } } } |
Data Annotations usados na definição
da classe Curso: A Anootation [Table("Curso")] define o nome da tabela que será gerada; A Annotation [DatabaseGenerated(DatabaseGeneratedOption.Identity)] A Annotation [StringLength(50)] define que o campo string cursoNome terá um tamanho de 50 caracteres; A Annotation [Required(ErrorMessage = "O nome do curso é obrigatório")] define que o campo cursoNome do curso é obrigatório; |
Vamos agora entender o que foi feito e o por quê ?
Definimos as 2 classes do nosso domínio pois o Entity Framework vai usar essa informação para gerar o mapeamento objeto relacional , criar o banco de dados e as tabelas para a nossa aplicação ASP .NET. Esse recurso chama-se Code-First (o código primeiro) e indica que partimos das definições de nossas classes de domínio para gerar o banco de dados e as tabelas e o contexto com o mapeamento objeto relacional.
Observe que todas as classes utilizam o namespace System.ComponentModel.DataAnnotations. Mas o para que serve isso ?
Os Data annotations são usados para definir atributos e validação nas classes alterando assim a convenção padrão usada pelo Entity Framework 4.1.
Os
atributos Data Annotation foram introduzido no .NET 3.5
como uma forma de adicionar a validação para as classes usadas por
aplicações ASP.NET. Desde aquela época, o RIA Services começou a usar
anotações de dados e eles agora fazem parte do Silverlight também. No
EF 4.0 o Code-First permite que você construa um EDM usando código
(C#/VB .NET) e também permite realizar a validação com atributos Data
Annotations. Para este
recurso devemos usar o namespace System.ComponentModel.DataAnnotations
pois é ele que provê atributos de classes
(usados para definir metadados) e métodos que podemos usar em nossas
classes para alterar as convenções padrão e definir um comportamento
personalizado que pode ser usado em vários cenários. A seguir temos a
relação das principais Annotations suportadas pelo Entity Framework
4.1: |
Então quando o Entity Framework encontrar as nossas definições de atributos e validações ele vai adotar a convenção que definimos e não a padrão que ele seguiria se apenas tivéssemos definidos as classes sem as anotações. Usamos os seguintes atributos na definição de nossas classes:
Mas o
que vem a ser 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. E quais seriam então essas convenções ??? Segue um resumo :
|
Na definição da classe Aluno poderíamos usar o atributo CustomValidation que permite definirmos uma classe customizada para realizar a validação. Como exemplo poderíamos ter definido uma classe interna usando o modificador sealed , que não permite que outras classes herdem desta classe.
Abaixo um exemplo onde a classe Validacao , realiza a validação da propriedade alunoNome:
internal sealed class Validacao { public static ValidationResult ValidarNome(string alunoNome) { if (alunoNome.Length > 3) return ValidationResult.Success; return new ValidationResult("O nome deve ter mais que 3 caracteres !"); } } |
Usando o atributo : [CustomValidation] [ Required, CustomValidation(typeof(Validacao), "ValidarNome")]public string alunoNome { get; set; } Esse atributo exige que uma classe seja criada usando
métodos estáticos que retornam um objeto do tipo
ValidationResult. |
Além das validações feitas com atributos podemos também usar a API Fluente e através da implementação da interface IValidatebleObject.(Assunto para outro artigo)
Nas classes definidas usamos as propriedades do tipo virtual para indicar que um tipo complexo (Aluno e Curso) possui um relacionamento através de uma chave estrangeira (ForeignKey) de forma que o EF vai usar esta propriedade como propriedade de navegação entre as entidades. Ex: Aluno.Curso.cursoNome .
Definimos também a propriedade Alunos como do tipo ICollection para indicar um relacionamento um-para-muitos. Assim para cada Curso existem muitos alunos.
Para podermos acessar o banco de dados vamos precisar definir um contexto.
Definindo o Contexto
Agora vamos definir uma classe que irá usar herdar da API DbContext e referenciar as classes que acabamos de criar
Selecione a pasta Model e no menu Project selecione Add Class e a seguir informe o nome Contexto.cs e clique no botão Add;
A seguir defina o código abaixo neste classe:
using System.Data.Entity; namespace Escola_CRUD_EF41.Model{ public
class
Contexto
: DbContext
public
Contexto() public
DbSet<Aluno>
Alunos { get;
set;
} |
Um dos recursos do EF
4.1 são as duas classes : ObjectContext e ObjectSet; - 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; O DbSet é um invólucro para ObjectSet.
|
A nossa classe Contexto herda de DbContext e define as propriedades Alunos, Cursos e Professores com as quais temos acesso as tabelas do banco de dados.
O construtor da classe define o nome do banco de dados que será criado pelo Entity Framework.
Isso é tudo que você precisa para iniciar a persistência e a consulta aos dados. Mas podemos melhorar...
Vamos usar outro recurso do Entity Framework que é o inicializador do banco de dados onde vamos definir a criação e carga dos dados iniciais.
Como já disse o EF irá criar um banco de dados com o nome EscolaMacoratti_CodeFirst que definimos no construtor da classe de contexto: Contexto.
Vamos então criar outra classe para iniciar o banco de dados e nela vamos definir as seguintes regras:
– O EF vai se conectar em uma instância padrão do
SQL Express (./SQLEXPRESS) criando o banco de dados
EscolaMacoratti_CodeFirst
se ele ainda não existir;
– O nome do banco de dados será o definido na classe de contexto com o
construtor 'base' ou então será o nome da classe.(conforme já
mostrei no artigo :
Entity
Framework 4 - Usando POCO,
Code First e as convenções padrão)
- O EF deverá implementar os requisitos que definimos via Data Annotations;
Nota:Lembre-se que até agora ainda não configuramos uma string de conexão no arquivo web.config.
Selecione a pasta Model e no menu Project selecione Add Class e a seguir informe o nome InicializaBD.cs e clique no botão Add;
A seguir defina o código abaixo nesta classe:
using System.Data.Entity;namespace Escola_CRUD_EF41.Model{ public class InicializaBD { public static void geraTabelas(bool excluiBD) { using (Contexto _contexto = new Contexto()) { if (excluiBD) _contexto.Database.Delete();
_contexto.Cursos.Add(curso);
_contexto.Alunos.Add(aluno); _contexto.SaveChanges(); } } } } |
A classe InicializaBD define o método estático geraTabelas(bool excluiBD) que recebe um parâmetro boleano que indica se vamos excluir o banco de dados gerado. Para isso usamos o método Delete da classe DataBase do contexto.
Definimos a seguir instâncias da classe Curso e Aluno atribuindo valores e em seguida persistindo as informação no banco de dados via método SaveChanges().
Falta agora definir onde vamos chamar a classe InicializaBD. Como estamos criando uma aplicação ASP .NET o arquivo Global.asax seria um ótimo local mas vou fazer diferente.
Vou incluir dois WebForms no projeto:
Selecione o projeto e no menu Project -> Add New Item inclua um novo WebForm com o nome Default.aspx. Repita o processo acima e inclua um novo WebForm chamado ExibeDados.aspx.
Abaixo temos o leiaute do WebForm Default.aspx:
A seguir inclua o código abaixo no arquivo code-behind Default.aspx.cs:
using Escola_CRUD_EF41.Model; namespace Escola_CRUD_EF41 { public partial class Default : System.Web.UI.Page { protected void btnGeraBD_Click(object sender, EventArgs e) { if (IsPostBack) { try { InicializaBD.geraTabelas(true); lblmensagem.Text = "Banco de dados e tabelas criados."; } catch (Exception ex) { lblmensagem.Text = " Erro : " + ex.Message; } } } protected void btnExibeDadaos_Click(object sender, EventArgs e) { Response.Redirect("~/ExibeDados.aspx"); } } } |
O código do evento Click do botão - Criar Banco de dados e tabelas - chama o método geraTabelas(true) passando o parâmetro true e com isso indicando que desejamos excluir o banco de dados existente; O evento Click do botão - Exibir Dados Existentes - irá chamar o formulário web ExibeDados.aspx. |
A seguir temos o leiaute do WebForm ExibeDados.aspx:
A seguir inclua o código abaixo no arquivo code-behind ExibeDados.aspx.cs :
using System;using System.Linq;using Escola_CRUD_EF41.Model;namespace Escola_CRUD_EF41{ public partial class ExibeDados : System.Web.UI.Page { protected void Page_Load(object sender, EventArgs e) { using (var contexto = new Contexto()) { GridView1.DataSource = contexto.Cursos.ToList(); GridView1.DataBind(); } } } } |
O código ao lado colocado no evento Load do formulário irá criar um a instância do Contexto e obter a lista de Cursos exibindo no controle GridView. |
Defina a página Default.aspx como sendo a página inicial do projeto (Set as Start Page) e execute o projeto:
Você verá a página Default.aspx exibindo os dois botões. Clique no botão para criar o banco de dados, e, após alguns segundos, você verá uma mensagem de sucesso:
Após isso clique no botão para exibir dados e a página ExibeDados.aspx será chamada exibindo os cursos gravados na tabela Curso:
Agora vamos verificar se o Entity Framework foi obediente e seguiu as nossas anotações.
Vamos verificar se isso é realmente verdade abrindo o SQL Server Management Studio e espiando o nosso SQL Server .
Abaixo vemos o banco de dados e as tabelas aluno o curso criadas :
Observe em cada tabela o campo chave primária, os nomes dos campos e os
campos chave estrangeira. Confira e você vai ver que ele fez tudo direitinho seguindo nossas instruções usando o Data Annotations. |
Selecionando o banco de dados e realizando uma consulta SELECT nas tabelas iremos constatar que os registros foram persistidos nas tabelas:
Tabela Aluno |
Tabela Curso |
E como prometemos observando o código não vimos nenhuma instrução SQL.
Em resumo as tarefas realizadas pelo EF 4.1 foram:
Se você chegou até aqui e constatou como é simples trabalhar com acesso a dados usando o Entity Framework pode se interessar pelo próximo artigo onde irei mostrar do como criar uma aplicação ASP .NET com acesso a dados usando os recursos do Ef 4.1.
Na segunda parte do artigo vamos realizar as operações CRUD usando ASP .NET e o Entity Framework 4.1 - Entity Framework 4.1 - ASP .NET com Code-First (C#) - II
Pegue o projeto completo aqui : Escola_CRUD_EF41.zip
"Portanto agora nenhuma condenação há para os que estão em Cristo Jesus, que não andam segundo a carne, mas segundo o espírito." Romanos 8:1
Referências: