Code First para um novo banco de dados

Este vídeo e passo a passo fornecem uma introdução ao desenvolvimento do Code First direcionado a um novo banco de dados. Esse cenário inclui direcionar um banco de dados que não existe e o Code First será criado ou um banco de dados vazio ao qual o Code First adicionará novas tabelas. O Code First permite que você defina seu modelo usando classes C# ou VB.Net. A configuração adicional pode ser executada opcionalmente usando atributos em suas classes e propriedades ou usando uma API fluente.

Assista ao vídeo

Este vídeo fornece uma introdução ao desenvolvimento do Code First direcionado a um novo banco de dados. Esse cenário inclui direcionar um banco de dados que não existe e o Code First será criado ou um banco de dados vazio ao qual o Code First adicionará novas tabelas. O Code First permite que você defina seu modelo usando classes C# ou VB.Net. A configuração adicional pode ser executada opcionalmente usando atributos em suas classes e propriedades ou usando uma API fluente.

Apresentado por: Rowan Miller

Vídeo: WMV | MP4 | WMV (ZIP)

Pré-Requisitos

Você precisará ter pelo menos o Visual Studio 2010 ou o Visual Studio 2012 instalado para concluir este passo a passo.

Se você estiver usando o Visual Studio 2010, também precisará ter o NuGet instalado.

1. Criar o aplicativo

Para simplificar, criaremos um aplicativo de console básico que usa Code First para executar o acesso a dados.

  • Abra o Visual Studio
  • Arquivo -> Novo -> Projeto
  • Selecione Windows no menu à esquerda e Aplicativo de Console
  • Insira CodeFirstNewDatabaseSample como o nome
  • Selecione OK

2. Criar o Modelo

Vamos definir um modelo muito simples usando classes. Estamos apenas definindo-as no arquivo Program.cs, mas em um aplicativo do mundo real, você dividiria suas classes em arquivos separados e, provavelmente, em um projeto separado.

Abaixo da definição da classe Program em Program.cs, adicione as duas classes a seguir.

public class Blog
{
    public int BlogId { get; set; }
    public string Name { get; set; }

    public virtual List<Post> Posts { get; set; }
}

public class Post
{
    public int PostId { get; set; }
    public string Title { get; set; }
    public string Content { get; set; }

    public int BlogId { get; set; }
    public virtual Blog Blog { get; set; }
}

Você observará que estamos tornando as duas propriedades de navegação (Blog.Posts e Post.Blog) virtuais. Isso habilita o recurso Carregamento lento do Entity Framework. O carregamento lento significa que o conteúdo dessas propriedades será carregado automaticamente do banco de dados quando você tentar acessá-las.

3. Criar um Contexto

Agora é hora de definir um contexto derivado, que representa uma sessão com o banco de dados, permitindo que consultemos e salvemos dados. Definimos um contexto que deriva de System.Data.Entity.DbContext e expõe um DbSet<TEntity> tipado para cada classe em nosso modelo.

Agora estamos começando a usar tipos do Entity Framework, portanto, precisamos adicionar o pacote NuGet EntityFramework.

  • Projeto –> Gerenciar Pacotes NuGet… Observação: se você não tiver a opção Gerenciar Pacotes NuGet... deverá instalar a versão mais recente do NuGet
  • Selecione a guia Online
  • Selecione o pacote EntityFramework
  • Clique em Instalar

Adicione uma instrução using para System.Data.Entity na parte superior de Program.cs.

using System.Data.Entity;

Abaixo da classe Post em Program.cs, adicione o contexto derivado a seguir.

public class BloggingContext : DbContext
{
    public DbSet<Blog> Blogs { get; set; }
    public DbSet<Post> Posts { get; set; }
}

Aqui está uma listagem completa do que Program.cs deve conter agora.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Data.Entity;

namespace CodeFirstNewDatabaseSample
{
    class Program
    {
        static void Main(string[] args)
        {
        }
    }

    public class Blog
    {
        public int BlogId { get; set; }
        public string Name { get; set; }

        public virtual List<Post> Posts { get; set; }
    }

    public class Post
    {
        public int PostId { get; set; }
        public string Title { get; set; }
        public string Content { get; set; }

        public int BlogId { get; set; }
        public virtual Blog Blog { get; set; }
    }

    public class BloggingContext : DbContext
    {
        public DbSet<Blog> Blogs { get; set; }
        public DbSet<Post> Posts { get; set; }
    }
}

Esse é todo o código que precisamos para começar a armazenar e recuperar dados. Obviamente, há muita coisa acontecendo nos bastidores e daremos uma olhada nisso em um momento, mas primeiro vamos vê-lo em ação.

4. Ler e Gravar Dados

Implemente o método Main em Program.cs conforme mostrado abaixo. Esse código cria uma nova instância do nosso contexto e a usa para inserir um novo Blog. Em seguida, usa uma consulta LINQ para recuperar todos os Blogs do banco de dados ordenado em ordem alfabética pelo Título.

class Program
{
    static void Main(string[] args)
    {
        using (var db = new BloggingContext())
        {
            // Create and save a new Blog
            Console.Write("Enter a name for a new Blog: ");
            var name = Console.ReadLine();

            var blog = new Blog { Name = name };
            db.Blogs.Add(blog);
            db.SaveChanges();

            // Display all Blogs from the database
            var query = from b in db.Blogs
                        orderby b.Name
                        select b;

            Console.WriteLine("All blogs in the database:");
            foreach (var item in query)
            {
                Console.WriteLine(item.Name);
            }

            Console.WriteLine("Press any key to exit...");
            Console.ReadKey();
        }
    }
}

Agora você pode executar e testar o aplicativo.

Enter a name for a new Blog: ADO.NET Blog
All blogs in the database:
ADO.NET Blog
Press any key to exit...

Onde estão os Meus Dados?

Por convenção, o DbContext criou um banco de dados para você.

  • Se uma instância local do SQL Express estiver disponível (instalada por padrão com o Visual Studio 2010), o Code First criou o banco de dados nessa instância
  • Se o SQL Express não estiver disponível, o Code First tentará usar o LocalDB (instalado por padrão com o Visual Studio 2012)
  • O banco de dados é nomeado de acordo com o nome totalmente qualificado do contexto derivado, em nosso caso é CodeFirstNewDatabaseSample.BloggingContext

Essas são apenas as convenções padrão e há várias maneiras de alterar o banco de dados que o Code First usa. Mais informações estão disponíveis no tópico Como o DbContext Descobre o Modelo e a Conexão de Banco de Dados. Você pode se conectar a esse banco de dados usando o Gerenciador de Servidores no Visual Studio

  • Exibir ->Gerenciador de Servidores

  • Clique com o botão direito do mouse em Conexões de Dados e selecione Adicionar Conexão…

  • Se você não tiver se conectado a um banco de dados do Gerenciador de Servidores antes, precisará selecionar o Microsoft SQL Server como a fonte de dados

    Select Data Source

  • Conecte-se ao LocalDB ou ao SQL Express, dependendo de qual você instalou

Agora podemos inspecionar o esquema que o Code First criou.

Schema Initial

O DbContext descobriu quais classes incluir no modelo examinando as propriedades DbSet que definimos. Em seguida, ele usa o conjunto padrão de convenções do Code First para determinar nomes de tabela e de coluna, determinar tipos de dados, localizar chaves primárias etc. Posteriormente, neste passo a passo, veremos como você pode substituir essas convenções.

5. Lidando com Alterações de Modelo

Agora é hora de fazer algumas alterações em nosso modelo, quando fazemos essas alterações, também precisamos atualizar o esquema de banco de dados. Para fazer isso, usaremos um recurso chamado Migrações do Code First ou Migrações para abreviar.

As Migrações nos permitem ter um conjunto ordenado de etapas que descrevem como atualizar (e fazer downgrade) nosso esquema de banco de dados. Cada uma dessas etapas, conhecida como migração, contém algum código que descreve as alterações a serem aplicadas. 

A primeira etapa é habilitar as Migrações do Code First para nosso BloggingContext.

  • Ferramentas -> Gerenciador de Pacotes da Biblioteca -> Console do Gerenciador de Pacotes

  • Execute o comando Enable-Migrations no Console do Gerenciador de Pacotes

  • Uma nova pasta Migrações foi adicionada ao nosso projeto que contém dois itens:

    • Configuration.cs – Esse arquivo contém as configurações que as Migrações usarão para migrar BloggingContext. Não precisamos alterar nada para este passo a passo, mas aqui é onde você pode especificar dados iniciais, registrar provedores para outros bancos de dados, alterar o namespace no qual as migrações são geradas etc.
    • <timestamp>_InitialCreate.cs – Essa é sua primeira migração, representa as alterações que já foram aplicadas ao banco de dados para levá-lo de um banco de dados vazio para um que inclui as tabelas Blogs e Postagens. Embora tenhamos deixado o Code First criar automaticamente essas tabelas para nós, agora que optamos pelas Migrações, elas foram convertidas em uma Migração. O Code First também registrou em nosso banco de dados local que essa migração já foi aplicada. O carimbo de data/hora no nome do arquivo é usado para fins de ordenação.

    Agora, vamos fazer uma alteração em nosso modelo, adicionar uma propriedade Url à classe Blog:

public class Blog
{
    public int BlogId { get; set; }
    public string Name { get; set; }
    public string Url { get; set; }

    public virtual List<Post> Posts { get; set; }
}
  • Execute o comando Add-Migration AddUrl no Console do Gerenciador de Pacotes. O comando Add-Migration verifica se há alterações desde sua última migração e realiza scaffolding de uma nova migração com quaisquer alterações encontradas. Podemos dar um nome às migrações; nesse caso, chamamos a migração de "AddUrl". O código do scaffolding está dizendo que precisamos adicionar uma coluna Url, que pode conter dados de cadeia de caracteres, à tabela dbo.Blogs. Se necessário, poderíamos editar o código do scaffolding, mas isso não é necessário nesse caso.
namespace CodeFirstNewDatabaseSample.Migrations
{
    using System;
    using System.Data.Entity.Migrations;

    public partial class AddUrl : DbMigration
    {
        public override void Up()
        {
            AddColumn("dbo.Blogs", "Url", c => c.String());
        }

        public override void Down()
        {
            DropColumn("dbo.Blogs", "Url");
        }
    }
}
  • Execute o comando Update-Database no console do Gerenciador de Pacotes. Esse comando aplicará todas as migrações pendentes ao banco de dados. Nossa migração initialCreate já foi aplicada, portanto, as migrações aplicarão apenas nossa nova migração AddUrl. Dica: você pode usar a opção –Verbose ao chamar Update-Database para ver o SQL que está sendo executado no banco de dados.

A nova coluna Url agora é adicionada à tabela Blogs no banco de dados:

Schema With Url

6. Anotações de dados

Até agora, acabamos de permitir que o EF descubra o modelo usando suas convenções padrão, mas haverá momentos em que nossas classes não seguirão as convenções e precisaremos ser capazes de executar mais configurações. Há duas opções para isso; Examinaremos as Anotações de Dados nesta seção e, em seguida, a API fluente na próxima seção.

  • Vamos adicionar uma classe User ao nosso modelo
public class User
{
    public string Username { get; set; }
    public string DisplayName { get; set; }
}
  • Também precisamos adicionar um conjunto ao nosso contexto derivado
public class BloggingContext : DbContext
{
    public DbSet<Blog> Blogs { get; set; }
    public DbSet<Post> Posts { get; set; }
    public DbSet<User> Users { get; set; }
}
  • Se tentarmos adicionar uma migração, obteríamos um erro dizendo "EntityType ''User'' não tem nenhuma chave definida. Defina a chave para esse EntityType." porque o EF não tem como saber que Username deve ser a chave primária de User.
  • Vamos usar as Anotações de Dados agora, portanto, precisamos adicionar uma instrução using na parte superior do Program.cs
using System.ComponentModel.DataAnnotations;
  • Agora, anote a propriedade Username para identificar que ela é a chave primária
public class User
{
    [Key]
    public string Username { get; set; }
    public string DisplayName { get; set; }
}
  • Use o comando Add-Migration AddUser para realizar scaffolding de uma migração para aplicar essas alterações ao banco de dados
  • Execute o comando Update-Database para aplicar a nova migração ao banco de dados

A nova tabela agora é adicionada ao banco de dados:

Schema With Users

A lista completa de anotações com suporte do EF é:

7. API fluente

Na seção anterior, analisamos o uso de Anotações de Dados para complementar ou substituir o que foi detectado por convenção. A outra maneira de configurar o modelo é por meio da API fluente do Code First.

A maioria das configurações de modelo pode ser feita usando anotações de dados simples. A API fluente é uma maneira mais avançada de especificar a configuração de modelo que abrange tudo o que as anotações de dados podem fazer além de algumas configurações mais avançadas não possíveis com as anotações de dados. As anotações de dados e a API fluente podem ser usadas em conjunto.

Para acessar a API fluente, substitua o método OnModelCreating em DbContext. Digamos que queiramos renomear a coluna onde User.DisplayName está armazenado para display_name.

  • Substitua o método OnModelCreating em BloggingContext pelo código a seguir
public class BloggingContext : DbContext
{
    public DbSet<Blog> Blogs { get; set; }
    public DbSet<Post> Posts { get; set; }
    public DbSet<User> Users { get; set; }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Entity<User>()
            .Property(u => u.DisplayName)
            .HasColumnName("display_name");
    }
}
  • Use o comando Add-Migration ChangeDisplayName para realizar scaffolding de uma migração para aplicar essas alterações ao banco de dados.
  • Execute o comando Update-Database para aplicar a nova migração ao banco de dados.

A coluna DisplayName agora foi renomeada para display_name:

Schema With Display Name Renamed

Resumo

Nesse passo a passo, analisamos o desenvolvimento do Code First usando um novo banco de dados. Definimos um modelo usando classes e, em seguida, usamos esse modelo para criar um banco de dados e armazenar e recuperar dados. Depois que o banco de dados foi criado, usamos as Migrações do Code First para alterar o esquema à medida que nosso modelo evoluiu. Também vimos como configurar um modelo usando as Anotações de Dados e a API fluente.