RSS feed
Desenvolvimento Antecipado de Código com Entity Framework 4 - ScottGu's Blog em Português

Desenvolvimento Antecipado de Código com Entity Framework 4


O .NET 4 vem com uma versão muito melhorada do Entity Framework (EF) - uma biblioteca de acesso a dados que reside no namespace System.Data.Entity.

Quando o Entity Framework foi primeiramente introduzido com o .NET 3.5 SP1, os desenvolvedores nos forneceram muitos comentários sobre coisas que eles achavam que estavam incompletas naquele primeiro lançamento.  O time de SQL fez um bom trabalho ouvindo esse retorno, e realmente focaram em aprimorar o EF que acompanha o .NET 4. 

Algumas das grandes melhorias no EF4 incluem:

  • Suporte a POCO: Agora você pode definir as entidades sem a necessidade de classes base ou atributos de persistência de dados
  • Suporte a Lazy Loading (carregamento tardio): Agora você pode carregar sub-objetos de um modelo sob demanda, ao invés de carregá-los antecipadamente
  • Suporte a N-Camadas e Auto-Rastreamento de Entidades: trata cenários em que as entidades são passadas entre camadas ou chamadas web sem estado.
  • Melhor suporte para Geração de SQL e SPROC: EF4 executa um código SQL melhor, e inclui uma melhor integração com SPROCs (stored procedures - procedimentos armazenados).
  • Suporte à Pluralização Automática: o EF4 inclui suporte à pluralização automática de tabelas (por exemplo Categorias -> Categoria).
  • Testabilidade Melhorada: o objeto de contexto do EF4 pode agora ser mais facilmente imitado usando interfaces.
  • Suporte melhorado para os Operadores LINQ: o EF4 agora oferece suporte completo para os operadores LINQ.

O Visual Studio 2010 também inclui um suporte muito mais rico para o designer e ferramentas do EF. O designer do EF no VS 2010 suporta tanto um estilo de desenvolvimento "database first" - "banco de dados primeiro" - onde você constrói a sua camada do modelo de dados através do designer a partir de um banco de dados existente. Ele também suporta um estilo de desenvolvimento "model first" - "modelo de dados primeiro" - onde você primeiro define o seu modelo de dados usando o designer, e então o usa para gerar um esquema de banco de dados a partir dele.

Desenvolvimento de Código Antecipado com o EF

Além de suportar o desenvolvimento baseado em um fluxo de trabalho que utiliza o designer, o EF4 também permite uma opção mais centrada em código a qual nos chamamos de Code-First Development ou "Desenvolvimento de Código Antecipado". O Desenvolvimento de Código Antecipado permite um fluxo de trabalho de desenvolvimento muito suave. Ele permite que você:

  • Desenvolva sem ter que abrir um designer ou definir um arquivo de mapeamento XM
  • Defina o seu modelo de objetos, bastando escrever "classes de objetos padrão", sem a necessidade de classes base
  • Use uma abordagem "Convenção sobre Configuração", que permite a persistência de dados sem ter que explicitamente configurar alguma coisa
  • Opcionalmente, substitua a persistência baseada em convenção passando a usar uma API de código fluente para personalizar completamente o mapeamento da persistência

O suporte ao desenvolvimento de código atencipado do EF é atualmente ativado com um download separado que roda por cima do núcleo interno do EF que acompanha o .NET 4. A CTP4 desta biblioteca foi liberada nesta semana e pode ser baixada aqui

Ela funciona com o VS 2010, e você pode usá-la com qualquer projeto do .NET 4 (incluindo ASP.NET Web Forms e ASP.NET MVC).

Tutorial passo a passo: Construindo a Aplicação NerdDinner utilizando uma abordagem Code-First (Código-Primeiro)

Ano passado eu escrevi um tutorial para a ASP.NET MVC 1.0 que foi publicado tanto online (em Inglês) como também em um livro. O tutorial ensinou como criar uma aplicação simples, chamada "NerdDinner", que oferece uma maneira fácil para as pessoas organizarem, hospedarem e coletarem respostas para convites de jantar de maneira online. Você pode ler o meu tutorial NerdDinner original para a ASP.NET V1 aqui. Uma versão atualizada do tutorial também está incluída no novo livro Professional ASP.NET MVC 2.

O tutorial NerdDinner utilizou uma abordagem "banco de dados primeiro", onde o esquema do banco foi definido em primeiro lugar, e em seguida, usamos um designer do Visual Studio para criar nosso modelo de objetos LINQ para SQL/LINQ para objetos para ele.  

A seguir vou demonstrar como podemos utilizar uma abordagem "code first" (código em primeiro lugar) usando o EF4 para construir a camada do modelo de dados NerdDinner e o esquema do banco de dados. Construiremos também uma aplicação CRUD usando a ASP.NET MVC.

imagem

Nós construiremos esta aplicação passo a passo. Um link para baixar a versão completa desta amostra está disponível no final deste post.

Passo 1: Criar uma Aplicação ASP.NET MVC 2 Nova e Vazia

Vamos começar criando um novo projeto ASP.NET MVC 2 no Visual Studio 2010. Escolha File ->New Project e use o modelo de projeto "ASP.NET MVC 2 Empty Web Application" para tanto.

Isso criará um projeto ASP.NET MVC 2 vazio que não tem controladores, modelos ou visões dentro dele:

imagem

Nós vamos trabalhar para definir o nosso "modelo" NerdDinner - que se refere aos objetos que representam os dados da nossa aplicação, bem como a lógica do domínio correspondente, que integra a validação e regras de negócios. O modelo é o "coração" de uma aplicação baseada em MVC, e fundamentalmente, guia o comportamento dela. Nós vamos criar esta camada do modelo usando as novas capacidades de "Codificação Antecipada" do EF4.

Passo 2: Criar o nosso modelo

Vamos assumir que nós não temos um banco de dados definido, e que estamos construindo nossa nova aplicação NerdDinner completamente a partir do zero.

Nós não precisamos começar com um banco de dados

Quando utilizamos um fluxo de trabalho baseado em codificação antecipada, nós não precisamos começar nossa aplicação criando um banco de dados ou especificando um esquema. Ao invés disso, podemos começar escrevendo classes padrão .NET que definem os objetos do modelo de domínio que são mais apropriados para nossa aplicação - sem nos preocuparmos em misturar lógica de persistência de dados dentro dessas classes.

Criando as classes do Modelo

NerdDinner é uma pequena aplicação, e nossas necessidades de armazenamento de dados para ela são muito simples. Nós queremos ser capazes de definir e armazenar informações de "Jantares" (Dinners) que se referem a eventos específicos que as pessoas podem participar. Também queremos ser capazes de definir e armazenar confirmações "RSVP" (responda por favor), que são usadas para controlar o interesse de uma pessoa em participar de um jantar específico.

Vamos criar duas classes (Dinner e RSVP) para representar estes conceitos. Nós vamos fazer isso adicionando duas novas classes no nosso projeto ASP.NET MVC - "Dinner" e "RSVP":

imagem

As classes do modelo "Dinner" e "RSVP" acima são "simples objetos da CLR" (também conhecidas como POCO). Elas não precisam derivar de qualquer classe base ou implementar interfaces, e as propriedades que elas expõem estão no padrão de tipos de dados do .NET.  Nenhum atributo de persistência de dados ou código de dados foi adicionado a elas.

A capacidade de definir classes do modelo sem ter que amarrá-las a um banco de dados específico, API de banco de dados, ou implementação de esquema de banco de dados é realmente poderosa - e nos dá muito mais flexibilidade para acessar os dados. Esta capacidade nos permite concentrar em nossa aplicação/necessidades do negócio sem termos que nos preocupar com a implementação da persistência dos dados. Também nos dá a flexibilidade para mudar o nosso esquema de banco de dados ou implementação de armazenamento no futuro - sem a necessidade de re-escrever os nossos objetos do modelo, ou o código que interage com eles.

Criando uma Classe de Contexto para Manipular a Persistência do Banco de Dados

Agora que nós definimos nossas duas classes POCO do modelo, vamos criar uma classe que podemos usar para lidar com a recuperação/persistência de instâncias de Dinner e RSVP de um banco de dados. 

Chamaremos esta classe de "NerdDinners". Ela deriva da classe base DbContext, e publica duas propriedades públicas - uma que expõe nossos objetos do tipo Dinner, e outra que expõe objetos do tipo RSVP:

imagem

As classes DbContext e DbSet utilizadas acima são fornecidas como parte da biblioteca de codificação antecipada do EF4. Você precisará adicionar uma referência ao assembly System.Data.Entity.CTP que está instalado no diretório \Program Files\Microsoft ADO.NET Entity Framework Feature CTP4\Binaries para referenciar estas classes. Você também vai querer adicionar uma referência ao namespace System.Data.Entity no topo da sua classe "NerdDinners".

Esse é todo o código que precisamos escrever

As três classes acima contêm todo o código necessário para implementar um modelo básico e uma camada de persistência de dados para nossa aplicação NerdDinner. Nós não precisamos configurar qualquer informação adicional de mapeamento do esquema do banco de dados, nem executar qualquer ferramenta, nem editar qualquer arquivo XML, nem utilizar qualquer designer a fim de começar a usar nossas classes para recuperar, atualizar e salvar os dados em um banco de dados.

Mapeamento de Persistência Baseado em Convenção

Nós não precisamos escrever nenhum código adicional, nem criar qualquer arquivo XML, nem usar quaisquer ferramentas para mapear as nossas classes do modelo para/e a partir de um banco de dados. Como, você pode perguntar, isso é possível?

Por padrão, a codificação antecipada do EF suporta uma abordagem "Convenção sobre configuração" que lhe permite depender de convenções de mapeamento comuns, em vez de ter de configurar explicitamente as coisas. Você pode substituir essas convenções se você quiser fornecer regras de mapeamento personalizadas para o banco de dados. Mas se você ao invés disso, utilizar as convenções padrão, você verá que a quantidade de código que você tem que escrever é muito pequena, e 90% dos cenários comuns "simplesmente funcionam" da maneira que você esperaria, sem qualquer código extra ou configuração.

Em nosso exemplo acima, a nossa classe de contexto NerdDinners irá por padrão mapear suas propriedades "Dinners" e "RSVPs" para as tabelas "Dinners" e "RSVPs" dentro um banco de dados. Cada linha dentro da tabela Dinnners será mapeada para uma instância da nossa classe "Dinner". Da mesma forma, cada linha da tabela RSVPs será mapeada para uma instância da nossa classe "RSVP". Propriedades dentro das classes "Dinner" e "RSVP" por sua vez serão mapeadas para as colunas dentro das respectivas tabelas "Dinners" e "RSVPs" do banco de dados.

Outras convenções padrão suportadas pelo EF incluem a capacidade de identificar automaticamente as chaves primárias e chaves estrangeiras, com base em padrões de nomenclatura comum (por exemplo: um ID ou propriedade DinnerID na classe Dinner será inferida como a chave primária). O EF também inclui convenções inteligentes para ligar relacionamentos de associação entre modelos. A equipe do EF tem um post que fala mais sobre como o conjunto de convenções padrão funcionam aqui (em Inglês).

Exemplos de Código de Como Usar Nosso Modelo

As três classes que criamos anteriormente contém todo o código necessário para implementar nosso modelo e persistência de dados para a aplicação NerdDinner. Vamos agora olhar alguns exemplos de código que mostram como podemos usar essas classes para executar cenários comuns de dados:

Pesquisando Dados usando Expressões LINQ

Nós podemos escrever expressões de consulta LINQ para recuperar dados de um banco de dados usando o seguinte código. As seguir nós estamos usando uma expressão LINQ para recuperar todos os jantares que ocorrem no futuro:

imagem

Nós também podemos tirar proveito das relações entre Dinners e RSVPs quando escrevemos nossas expressões LINQ. Observe a seguir como a nossa declaração "where" filtra jantares que possuem uma contagem de RSVP maior que 0:

imagem

Observe que o filtro "where" na consulta acima (onde estamos recuperando apenas os jantares que têm pelo menos uma RSVP) é executado no servidor de banco de dados - fazendo com que a consulta e a quantidade de dados que recuperamos seja muito eficiente.

Recuperando uma Única Instância

Podemos usar o método Single() de LINQ com uma consulta lambda para recuperar uma única instância de um jantar usando um código como a seguir:

imagem

Alternativamente, também podemos tirar proveito de um método Find() que o paradigma de codificação antecipada do EF expõe. Este método permite que você recupere facilmente uma instância com base na sua identificação:

imagem

Adicionando um novo Jantar

O código a seguir demonstra como criar e adicionar um novo jantar no banco de dados. Tudo o que precisamos fazer é instanciar um "novo" objeto do tipo Dinner, atribuir valores as suas propriedades, e, em seguida, adicioná-lo à propriedade Dinners do nosso objeto de contexto NerdDinners. A classe de contexto NerdDinner suporta o padrão de desenvolvimento "unity of work" (unidade de trabalho) que permite que você adicione vários modelos no contexto, e então chame o método "SaveChanges()" deste para persistir todas as alterações em um banco de dados como uma única transação atômica.

imagem

Atualizando um Jantar

O código abaixo demonstra como recuperar um jantar, atualizar uma de suas propriedades e, em seguida salvar as alterações de volta para o banco de dados:

imagem

Passo 3: Criar um Controlador ASP.NET MVC que utiliza o nosso Modelo

Vamos agora olhar para um cenário mais completo que envolve o nosso modelo, onde usamos uma classe de controlador para implementar a funcionalidade necessária para publicar uma lista de jantares programados e permitir aos usuários adicionar novos jantares:

imagem

Nós vamos implementar essa funcionalidade clicando com o botão direito do mouse sobre a pasta "Controllers" e selecionando a opção "Add->Controller" no menu. Vamos chamar nosso novo controlador "HomeController".

Vamos então adicionar três "métodos de ação" dentro dele que trabalham com o modelo NerdDinners que criamos anteriormente usando o paradigma de "codificação antecipada" do EF:

imagem

O método de ação "Index" acima recupera e processa uma lista de jantares programados. 

O método de ação "Create" permite aos usuários adicionar novos jantares. O primeiro método "Create" acima trata o cenário "HTTP GET" quando um usuário visita a URL /Home/Create, e envia um formulário "New Dinner" para ser preenchido. O segundo método "Create" manipula o cenário "HTTP POST" associado ao formulário - e trata de salvar o jantar no banco de dados. Se houver qualquer problemas de validação ele mostra novamente o formulário para o usuário com mensagens de erro apropriadas.

Adicionando Visões para nossos Controladores

Nosso próximo passo será adicionar dois "modelos de Visão" em nosso projeto - um para "Index" e outro para "Create". 

Nós vamos adicionar a visão "Index" em nosso projeto movendo o cursor do mouse para dentro do nosso método de ação Index em nosso controlador, e, em seguida, clicaremos com o botão direito e escolheremos a opção "Add View". Isso fará com que a janela de diálogo "Add View" apareça. Nós vamos especificar que queremos criar uma visão fortemente tipada, e que estaremos passando uma lista IEnumerable de objetos do tipo "Dinner" do modelo para esta:

imagem

Ao clicarmos em "Add", o Visual Studio irá criar a visão em Views/Home/index.aspx. Vamos então adicionar o seguinte código na visão - o qual gera uma lista <ul> de Dinners, e renderiza um hiperlink que aponta para nosso método de ação Create:

imagem

Iremos, em seguida, adicionar a visão "Create" em nosso projeto, movendo o cursor do mouse para dentro do nosso método de ação Create em nosso controlador, e, em seguida, clicaremos com o botão direito e escolheremos a opção "Add View". Dentro da janela de diálogo "Add View" vamos especificar que queremos criar uma visão fortemente tipada, e que estamos passando para esta um objeto do tipo Dinner. Também vamos indicar que queremos "descobrir automaticamente" suas propriedades usando um modelo de visão "Create":

imagem

Ao clicar no botão "Add", o Visual Studio irá criar um arquivo Views/Home/Create.aspx com algum conteúdo gerado automaticamente que cria um <form> HTML para o objeto "Dinner". Nós vamos ajustá-lo um pouco retirando o elemento de entrada para a propriedade DinnerID. O conteúdo final do nosso modelo de visão será parecido com este:

imagem

Temos agora implementado todo o código que precisamos escrever dentro do nosso Controlador e Visões para implementar a lista de jantares e a funcionalidade de criação de novos jantares dentro da nossa aplicação web.

Etapa 4: O Banco de Dados

Nós escrevemos nosso código. Agora vamos executar a aplicação. 

Mas e o banco de dados?

Nós ainda não temos um banco de dados - e não precisamos de um até agora porque o nosso fluxo de trabalho de desenvolvimento que usa "codificação antecipada" ou "código em primeiro lugar" não nos obrigou a ter um banco de dados para definirmos e usarmos nossas classes do modelo.

Mas vamos precisar de um banco de dados quando nós realmente executarmos nossa aplicação e quisermos armazenar nossos objetos Dinner e RSVP. Podemos criar o banco de dados de duas maneiras:

  1. Nós mesmos manualmente podermos criar e definir o esquema usando uma ferramenta de banco de dados (por exemplo, SQL Server Management Studio ou Visual Studio)
  2. Criar e gerar o esquema automaticamente a partir do nosso modelo de classes usando a biblioteca de codificação antecipada do EF.

Esta segunda opção é muito legal e é a que vamos usar para a nossa aplicação NerdDinner.

Configurando nossa String de Conexão do Banco de Dados

Para começar, nós configuramos uma string de conexão para apontar para onde queremos que o nosso banco de dados resida. Nós vamos fazer isso adicionando uma string de conexão chamada "NerdDinners" no arquivo web.config da nossa aplicação assim: 

imagem 

Por padrão, quando você cria uma classe DbContext usando a codificação antecipada do EF, ele vai procurar por uma string de conexão que corresponda ao nome da classe do contexto. Já que o nome da nossa classe de contexto é "NerdDinners", ele irá procurar e usará por padrão a string de conexão "NerdDinners" descrita acima, quando o contexto for instânciado dentro da nossa aplicação ASP.NET.

Tirando vantagem do SQL CE 4

Você pode usar bases de dados diferentes com a codificação antecipada do EF - incluindo o SQL Server, SQL Express e MySQL.

Há duas semanas atrás eu escrevi (em Inglês) sobre o trabalho que estamos fazendo para permitir que o engine do banco de dados SQL CE 4 funcione dentro da ASP.NET. SQL CE 4 é um banco de dados leve e baseado em arquivos que é gratuito, simples de configurar, e pode ser incorporado em suas aplicações ASP.NET. Ele suporta ambientes de hospedagem de baixo custo, e permite que bancos de dados sejam facilmente migrados para o SQL Server.

O SQL CE pode ser uma opção útil para se usar quando você está nos estágios iniciais de definição (e redefinindo) sua camada do modelo de dados - e quer ser capaz de rapidamente criar e recriar seu banco de dados durante estes processos. Nós vamos usar o SQL CE 4 para começar à medida em que desenvolvemos nossa aplicação NerdDinner. Podemos mais tarde, opcionalmente, alterar a string de conexão para usar o SQL Express ou SQL Server para instalarmos a aplicação no ambiente de produção - sem ter que modificar uma única linha de código dentro de nossa aplicação.

A string de conexão que eu especifiquei acima aponta para um arquivo de banco de dados NerdDinners.sdf, e especifica o provedor de banco de dados SQL CE 4. Para que isso funcione você precisa instalar o SQL CE 4 - quer através do Instalador SQL CE ou instalando WebMatrix (que o inclui por padrão). o banco de dados SQL CE 4 é um download pequeno que leva apenas alguns segundos para instalar.

Importante: Na string de conexão acima eu estou indicando que queremos criar o arquivo NerdDinners.sdf dentro da pasta |DataDirectory| - a qual em uma aplicação ASP.NET é a pasta \App_Data\ imediatamente abaixo do diretório da aplicação. Por padrão, o modelo de projeto da "Aplicação Web ASP.NET MVC Vazia" não cria este diretório. Você precisará criar explicitamente esse diretório dentro de seu projeto (clique com o botão direito do mouse sobre o projeto e escolha a opção "Add->ASP.NET Folder>Add_Data").

Criação Automática do Esquema do Banco de Dados

O paradigma de codificação antecipada do EF suporta a capacidade de gerar automaticamente o esquema do banco de dados criando bancos de dados a partir de classes do modelo - o que lhe permite evitar a execução manual destes passos.

Isso acontece por padrão se sua string de conexão apontar para qualquer arquivo de banco de dados SQL CE ou SQL Express que ainda não exista no disco. Você não precisa executar nenhum passo manual para que isto aconteça.

Para ver isso em ação, podemos pressionar F5 para executar nossa aplicação NerdDinner. Isto abrirá um browser na URL raiz "/" da nossa aplicação. Você deverá ver uma tela igual a mostrada a seguir:

imagem

A URL "/" quando solicitada para a nossa aplicação invocou o método de ação HomeController.Index() - o qual instanciou e consultou nosso objeto de contexto NerdDinners para recuperar todos os jantares programados a partir de nossa base de dados. Como o arquivo do banco de dados NerdDinners.sdf ainda não existia, a biblioteca de codificação antecipada do EF gerou o mesmo automaticamente para nós. Esta usou nosso objeto de contexto NerdDinners para inferir o esquema do banco de dados gerado. 

Para ver o arquivo do banco de dados SQL CE que foi gerado, clique no botão "Show all Files" (Mostrar todos os arquivos) dentro do Solution Explorer no Visual Studio, e pressione o botão "Update" (Atualizar) e expanda a pasta App_Data:

imagem 

Nós estaremos lançando uma atualização para o VS 2010, no futuro, que lhe permitirá abrir e editar bases de dados SQL CE 4 na tab "Server Explorer" (como você faz hoje, com banco de dados SQL). Isto permitirá que você possa facilmente ver (e, opcionalmente, ajustar) o esquema e o conteúdo do banco de dados. Até lá, você pode opcionalmente usar as ferramentas de banco de dados dentro da WebMatrix para examinar o conteúdo do arquivo de dados do SQL CE 4.

Nós não especificamos nenhuma regra de mapeamento de persistência personalizada em nosso contexto NerdDinners - assim o banco de dados que foi gerado seguiu o padrão da codificação antecipada do EF no que diz respeito às convenções de nomenclatura para mapear o esquema. Se tivéssemos especificado qualquer regra de mapeamento customizada, a biblioteca de codificação antecipada do EF teria honrado as mesmas e geraria um banco de dados que corresponderia a tais regras.

Só para refrescar nossa memória - aqui estão as duas classes POCO do modelo e a classe do contexto NerdDinners que definimos anteriormente:

imagem

A seguir estão as tabelas que foram adicionadas quando executamos nossa aplicação e o banco de dados criado automaticamente com base no modelo acima:

imagem 

A definição da tabela "Dinners" é mostrada a seguir. Os nomes das colunas e os tipos de dados mapeiam para as propriedades da classe Dinner que nós definimos. A coluna DinnerID também foi configurada para ser tanto uma chave primária e uma coluna de identidade:

imagem

A definição da tabela "RSVPs" é mostrada a seguir. Os nomes das colunas e tipos de dados mapeiam para as propriedades da classe RSVP que nós definimos. A coluna RsvpID também foi configurada para ser tanto uma chave primária e uma coluna de identidade:

imagem

Um relacionamento do tipo um para muitos (chave primária/chave estrangeira) também foi estabelecido entre Dinners e RSVPs. A biblioteca de codificação antecipada do EF inferiu que este relacionamento deve ser estabelecido porque nossa classe Dinner tem uma propriedade do tipo ICollection<RSVP> chamada RSVPs, e a classe RSVP tem uma propriedade Dinner.  

Preenchendo o Banco de Dados com alguns Jantares (Dinners)

Vamos agora criar e adicionar alguns jantares em nosso banco de dados. Nós vamos fazer isso clicando no link "Create New Dinner" na nossa home-page para navegar para o nosso formulário/visão "Create":

imagem

Quando clicamos no botão "Create", o nosso novo jantar será salvo no banco de dados. Podemos repetir este processo várias vezes para registrar vários jantares diferentes  Cada novo jantar que criarmos será mantido dentro do nosso banco de dados e aparecerá na nossa lista de jantares programados na Home page:

imagem 

Passo 5: Mudando nosso Modelo

Vamos evoluir e refatorar continuamente nosso modelo, de acordo com o crescimento de nossa aplicação. A biblioteca code-only (apenas-código) do EF inclui alguns recursos de desenvolvimento legais que tornam mais fácil coordenar essa evolução com um banco de dados de desenvolvimento.

Adicionando uma nova Propriedade para o modelo Dinner

Vamos seguir passo a passo fazendo uma simples mudança em nossa classe Dinner. Especificamente, nós vamos adicionar uma propriedade adicional em nossa classe Dinner chamada "Country" (País):

imagem

Agora que fizermos esta mudança, vamos pressionar F5 no Visual Studio para construir e re-executar a aplicação. Quando fazemos isso nós vamos ver a seguir mensagem de erro:

imagem

Esta mensagem de erro ocorre porque nós mudamos a estrutura da nossa classe Dinner, e nosso modelo de objeto já não apresenta a mesma forma que a tabela "Dinners" que automaticamente criamos dentro do nosso banco de dados. 

Quando o EF cria automaticamente um banco de dados para você, por padrão ele adiciona uma tabela chamada "EdmMetadata" no banco de dados que controla a forma dos objetos do modelo que foram usados para criar automaticamente o esquema do banco de dados para você: 

imagem

A mensagem de erro acima ocorre quando o EF detecta que você fez uma mudança em um objeto do modelo e ele agora está fora de sincronia com o banco de dados que foi criado automaticamente para você. 

Re-sincronizando nossas Classes do Modelo com o Banco de Dados

Existem algumas maneiras pelas quais nós podemos "re-sincronizar" os objetos de nosso modelo com o banco de dados

  • Podemos atualizar manualmente o nosso esquema do banco de dados para coincidir com os nossos modelos
  • Podemos excluir manualmente o nosso arquivo de banco de dados, re-executar a aplicação, e o EF automaticamente re-criará o banco de dados
  • Podemos ativar um recurso da codificação antecipada do EF que atualiza automaticamente o nosso banco de dados sempre que nós efetuarmos uma mudança em os nossos modelos

Vejamos como podemos utilizar essa última opção automática com a nosso aplicação NerdDinner.

O recurso RecreateDatabaseIfModelChanges (Recriar o banco de dados se o modelo for modificado)

A CTP 4 da biblioteca de codificação antecipada do EF inclui um recurso útil no tempo de desenvolvimento que permite que você automaticamente re-crie o banco de dados quando você fizer modificações em suas classes do modelo. Quando você ativá-lo, o EF identifica quando qualquer uma das classes do modelo que foram usadas para criar automaticamente um banco de dados são modificadas, e quando isso acontece ele pode recriar seu banco de dados para que o mesmo coincida com a forma da classe - sem que você tenha que executar algum passo manualmente.

Esse recurso é especialmente útil quando você é o primeiro a desenvolver uma aplicação, uma vez que lhe dá a liberdade e flexibilidade para rapidamente refazer e reestruturar seu modelo de código como quiser - sem ter que realizar qualquer trabalho manual para manter o seu esquema do banco de dados em sincronia ao longo do caminho. Ele funciona especialmente bem com o SQL CE - uma vez que é um banco de dados baseado em arquivo que pode ser descartado e recriado em tempo real em menos de um segundo. Isso pode permitir um fluxo de trabalho de desenvolvimento extremamente fluído.

A maneira mais fácil para habilitar essa capacidade é adicionando uma chamada Database.SetInitializer() no tratador do evento Application_Start() dentro da nossa classe Global.asax:

imagem

Isto informa ao EF que ele deve recriar nossa base de dados NerdDinners.sdf para que a mesma seja compatível com o nosso modelo NerdDinners em qualquer momento que nossas classes do modelo mudem de forma. Agora, quando reexecutarmos nossa aplicação, vamos deixar de receber aquela mensagem de erro nos informando que o nossas classes do modelo e o banco de dados estão fora de sincronia. O EF, irá ao invés de exibir a mensagem, automaticamente re-criar o banco de dados para nós de forma que este seja compatível com a nova forma das nossas classes do modelo e nossa aplicação funcionará perfeitamente:

imagem

Adicionando Dados Iniciais em Bancos de Dados Criados Automaticamente

Uma das coisas que você deve ter notado na tela acima é que nós perdemos nossos dados de jantares quando recriamos o banco de dados. Isso ocorre porque o comportamento automático de "RecreateDatabaseIfModelChanges" não se destina a cenários de produção onde você deseja "migrar" os dados existentes de um esquema para outro. Em vez disso, este recurso é projetado para cenários de desenvolvimento onde você deseja que o banco de dados seja rapidamente e automaticamente atualizado para você - sem que você tenha que executar passos manuais ou especificar as regras de migração para o fazer. 

Nota: Estamos trabalhando separadamente para fornecer melhor suporte à migração de dados para cenários onde você está trabalhando com dados de produção e deseja versionar o esquema do banco de dados. Nós achamos que este cenário é diferente deste recurso existente para o tempo de desenvolvimento que eu estou descrevendo aqui. A capacidade de migração de dados não está ativada ainda com a CTP desta semana.

O EF nos fornece a capacidade de opcionalmente "adicionar dados iniciais" em nosso banco de dados (dados padrão/de teste) a qualquer momento em que o banco de dados seja criado/recriado. Acho que esse recurso é realmente útil, pois ele me permite refazer um modelo, e então rapidamente executar a aplicação para testar um cenário - sem que eu tenha que entrar manualmente com um monte de dados de teste para fazê-lo.

Nós podemos "adicionar dados iniciais" em nosso banco de dados NerdDinners com dados padrão, escrevendo uma classe "NerdDinnersIntializer", igual a mostrada a seguir. Estou usando esta classe para criar dois "jantares de amostra" e adiciono os mesmos em nosso banco de dados da seguinte forma:

imagem

Podemos, então, atualizar a chamada Database.Initializer() que adicionamos em nosso arquivo Global.asax para usar esta classe "NerdDinnersInitializer" na inicialização da aplicação:

imagem

E agora a qualquer hora que fizermos uma alteração em uma das nossas classes do modelo NerdDinner, o banco de dados será automaticamente descartado e recriado para coincidir com os nossas classes do modelo, e teremos dois jantares já inseridos no banco de dados para fins de teste:

imagem

Fácil Refatoração

Os recursos acima tornam realmente fácil evoluir e refatorar seu código no tempo de desenvolvimento - sem ter que utilizar ferramentas ou executar scripts manualmente para manter seu banco de dados em sincronia com as mudanças de seu código.

Devido as nossas classes do modelo, expressões LINQ, e "dados iniciais" de teste serem fortemente tipificados/tipados, também podemos tirar proveito do suporte de ferramentas de refatoração dentro do Visual Studio para rapidamente e automaticamente aplicar alterações em toda a nossa base de código de uma maneira rápida e fácil.

Passo 6: Adicionando Regras Validação

Nós construímos uma simples e boa aplicação para entrada de dados.

Um problema com ela, porém, é que não temos atualmente nenhum tipo de validação de dados de entrada em vigor para garantir que os campos sejam preenchidos corretamente dentro da nosso formulário de Criação de Jantar. Vamos corrigir isso.

Adicionando Validação usando DataAnnotations

Regras de validação em uma aplicação baseada em ASP.NET MVC geralmente são expressas de uma maneira melhor dentro de um modelo. Isso permite que elas sejam mantidas em um único lugar, e que sejam executadas em qualquer número de controladores e visões que possam interagir com elas. A ASP.NET MVC permite que você implemente regras de validação usando uma variedade de mecanismos diferentes, e é flexível o suficiente para suportar praticamente qualquer esquema de validação que você deseje usar. 

A ASP.NET MVC 2 inclui suporte nativo para usar a biblioteca de regras de validação do .NET System.ComponentModel.DataAnnotations - a qual permite que você declarativamente aplique regras de validação em classes do modelo usando atributos de validação. Você pode aprender mais sobre esse recurso em um post anterior que eu escrevi . Vamos aproveitar essa abordagem para permitir a validação dos dados de entrada para a nossa aplicação NerdDinner.

Vamos voltar na classe Dinner que definimos anteriormente e vamos adicionar alguns atributos de validação em suas propriedades (nota: é preciso adicionar uma referência para o namespace "using System.ComponentModel.DataAnnotations" tabém):

imagem

O atributo de validação [Required] (Obrigatório) indica que uma propriedade particular deve ser especificada. O atributo de validação [StringLength] (Comprimento da String) permite-nos indicar um comprimento máximo de uma propriedade particular do tipo string. O atributo de validação [RegularExpression] (Expressão Regular) permite-nos indicar que uma propriedade particular do tipo string deve coincidir com uma expressão regular especificada, a fim de ser válida - neste caso, um endereço de e-mail.

Cada um dos atributos de validação suporta uma propriedade "ErrorMessage" (Mensagem de Erro) - a qual nos permite especificar uma mensagem de erro que deve ser exibida se a validação falhar. Esta mensagem pode ser inserida como uma string (como acima) ou e ser proveniente de um arquivo de recurso - o que lhe permite localizar (traduzir) a mensagem de erro facilmente em vários idiomas.

Referenciando alguns arquivos CSS e JavaScript

A última etapa será voltar em nosso modelo de visão Create.aspx para adicionarmos uma um elemento <link> que referência o arquivo Site.css no nosso projeto, bem como dois elementos <script> para referenciar dois arquivos JavaScript no nosso projeto. Também vamos adicionar uma linha de código para chamar o método Html.EnableClientValidation() antes que o nosso elemento <form> seja processado:

imagem

Estas alterações irão garantir que as mensagens de erro de validação que são exibidas na página sejam estilizadas (para torná-las mais visíveis), e que as regras de validação que aplicamos em nosso modelo sejam aplicadas tanto no cliente como servidor.

Executando a Aplicação

Vamos re-executar a aplicação e tentar criar um novo jantar. Vamos começar pressionando o botão "Create" sem valores preenchidos. Nós vemos agora as mensagens de erro de validação que aplicamos no nosso modelo aparecendo no navegador:

imagem

Devido a permitirmos a validação no lado do cliente com a ASP.NET MVC (uma linha de código que escrevemos acima), nossas mensagens de erro serão atualizadas e mudarão em tempo real:

imagem

Observe acima como nossa mensagem de erro de validação mudou no momento em que nosso campo "Title" ficou maior que 20 caracteres. Isto é porque nós temos uma propriedade [StringLength] em nossa propriedade Dinner.Title que indica um tamanho máximo permitido de 20 caracteres. Quando começamos a entrar um valor dentro do campo de texto "HostedBy", a nossa mensagem de erro também mudou de uma mensagem de erro "[Requred]" (que pede que você digite o seu endereço de e-mail) para uma mensagem de erro "[RegularExpression]" (que está nos informando que não temos um endereço de e-mail válido).

Estas regras de validação tanto funcionam tanto dentro do navegador (via JavaScript) como no servidor (o que nos permite proteger a nós mesmos, mesmo se alguém tentar contornar a validação JavaScript) - sem que tenhamos que fazer quaisquer mudanças em nossa classe de controlador. A habilidade de especificar essas regras uma única vez dentro do nosso modelo, e tê-las aplicadas em todos os lugares, é extremamente poderosa - e nos permitirá continuar a evoluir a nossa aplicação de uma forma muito limpa. 

Você pode aprender mais sobre estes recursos do Modelo de Validação da ASP.NET MVC e como eles funcionam aqui.

Download

Clique aqui para fazer o download e executar o exemplo de aplicação NerdDinnerReloaded que nós construímos neste post. A aplicação requer o VS 2010 (ou o Visual Web Developer 2010 Express que é gratuito). 

Importante: Você deve baixar e instalar o SQL CE 4 em sua máquina para que a aplicação de exemplo acima funcione. Você pode fazer o download da biblioteca de codificação antecipada do EF aqui. Nenhum destes downloads vai impactar sua máquina.

Resumo

O lançamento CTP4 da funcionalidade "Code-First" ou "Codificação Antecipada" do EF fornece uma maneira bastante agradável e centrada em código para trabalhar com dados. Ele traz consigo uma série de recursos de produtividade, bem como muito poder para o desenvolvimento. No tutorial de hoje, concentrei-me principalmente em algumas das novas melhorias de produtividade que foram liberadas com o lançamento da CTP4. Existem muitos outros cenários que poderíamos explorar incluindo sua API Fluent (Fluente) que permite regras de mapeamento de persistência personalizadas, o seu suporte melhorado para testabilidade, e outros recursos mais avançados.

Você pode fazer o download da CTP4 do EF Code-First desta semana aqui. Para saber ainda mais sobre o desenvolvimento com "EF Code-First" verifique esses posts do time do ADO.NET (todos em Inglês):

Espero que ajude,

Scott

PS Além do blog, eu também estou agora utilizando o Twitter para atualizações rápidas e para compartilhar links. Siga-me em: twitter.com/ScottGu.

 

Texto traduzido do post original por Leniel Macaferi.

Published Friday, July 16, 2010 6:35 AM by Leniel Macaferi

Comments

# re: Desenvolvimento Antecipado de Código com Entity Framework 4

Saturday, December 4, 2010 7:06 PM by Fernando Ferreira

Very good Tutorial!!! Many Thanks!!

# re: Desenvolvimento Antecipado de Código com Entity Framework 4

Thursday, April 28, 2011 2:08 PM by Junio

Excelente post, bom saber sobre estas novas formas de acesso a dados com Entity Framework.