Exercício - Configurar uma migração

Concluído

Nesta unidade, você cria classes de entidade C# que mapeiam para tabelas em um banco de dados SQLite local. O recurso de migrações do EF Core produz tabelas dessas entidades.

Uma migração fornece uma maneira de atualizar incrementalmente o esquema do banco de dados.

Obter os arquivos do projeto

Para começar, obtenha os arquivos do projeto. Você tem algumas opções para como obter os arquivos do projeto:

  • Usar Codespaces do GitHub
  • Clone o repositório GitHub

Se você tiver um tempo de execução de contêiner compatível instalado, também poderá usar a extensão Dev Containers para abrir o repositório em um contêiner com as ferramentas pré-instaladas.

Usar Codespaces do GitHub

Um espaço de código é um IDE hospedado na nuvem. Se você estiver usando o GitHub Codespaces, vá para o repositório em seu navegador. Selecione Código e, em seguida, crie um novo espaço de main código na ramificação.

Clone o repositório GitHub

Se você não estiver usando o GitHub Codespaces, poderá clonar o repositório do GitHub do projeto e, em seguida, abrir os arquivos como uma pasta no Visual Studio Code.

  1. Abra um terminal de comando e, em seguida, clone o projeto do GitHub usando o prompt de comando:

    git clone https://github.com/MicrosoftDocs/mslearn-persist-data-ef-core
    
  2. Vá para a pasta mslearn-persist-data-ef-core e, em seguida, abra o projeto no Visual Studio Code:

    cd mslearn-persist-data-ef-core
    code .
    

Rever o código

Agora que você tem os arquivos de projeto para trabalhar, vamos ver o que há no projeto e revisar o código.

  • O projeto de API Web ASP.NET Core está localizado no diretório ContosoPizza . Os caminhos de arquivo aos quais nos referimos neste módulo são relativos ao diretório ContosoPizza .
  • Services/PizzaService.cs é uma classe de serviço que define métodos de criação, leitura, atualização e exclusão (CRUD). Todos os métodos atualmente lançam System.NotImplementedException.
  • Em Program.cs, PizzaService está registrado no sistema de injeção de dependência ASP.NET Core.
  • Controllers/PizzaController.cs é um valor que ApiController expõe um ponto de extremidade para verbos HTTP POST, GET, PUT e DELETE. Esses verbos chamam os métodos CRUD correspondentes em PizzaService. PizzaService é injetado PizzaController no construtor.
  • A pasta Modelos contém os modelos que PizzaService e PizzaController usar.
  • Os modelos de entidade, Pizza.cs, Topping.cs e Sauce.cs, têm as seguintes relações:
    • Uma pizza pode ter uma ou mais coberturas.
    • Uma cobertura pode ser usada em uma ou em muitas pizzas.
    • Uma pizza pode ter um molho, mas um molho pode ser usado em muitas pizzas.

Criar a aplicação

Para criar o aplicativo no Visual Studio Code:

  1. No painel Explorer, clique com o botão direito do mouse no diretório ContosoPizza e selecione Abrir no Terminal Integrado.

    Um painel de terminal com escopo para o diretório ContosoPizza é aberto.

  2. Crie o aplicativo usando o seguinte comando:

    dotnet build
    

    O código deve ser compilado sem avisos ou erros.

Adicionar pacotes NuGet e ferramentas EF Core

O mecanismo de banco de dados com o qual você trabalha neste módulo é SQLite. SQLite é um mecanismo de banco de dados leve e baseado em arquivo. É uma boa escolha para desenvolvimento e testes, e também é uma boa escolha para implantações de produção em pequena escala.

Nota

Como mencionado anteriormente, os provedores de banco de dados no EF Core podem ser conectados. SQLite é uma boa escolha para este módulo porque é leve e multiplataforma. Você pode usar o mesmo código para trabalhar com diferentes mecanismos de banco de dados, como SQL Server e PostgreSQL. Você pode até mesmo usar vários mecanismos de banco de dados no mesmo aplicativo.

Antes de começar, adicione os pacotes necessários:

  1. No painel de terminal, execute o seguinte comando:

    dotnet add package Microsoft.EntityFrameworkCore.Sqlite
    

    Este comando adiciona o pacote NuGet que contém o provedor de banco de dados EF Core SQLite e todas as suas dependências, incluindo os serviços comuns do EF Core.

  2. Em seguida, execute este comando:

    dotnet add package Microsoft.EntityFrameworkCore.Design
    

    Este comando adiciona pacotes que são necessários para as ferramentas EF Core.

  3. Para concluir, execute este comando:

    dotnet tool install --global dotnet-ef
    

    Este comando instala dotnet efo , a ferramenta que você usa para criar migrações e andaimes.

    Gorjeta

    Se dotnet ef já estiver instalado, você pode atualizá-lo executando dotnet tool update --global dotnet-ef.

Modelos de andaime e DbContext

Agora você adiciona e configura uma DbContext implementação. DbContext é um gateway através do qual você pode interagir com o banco de dados.

  1. Clique com o botão direito do mouse no diretório ContosoPizza e adicione uma nova pasta chamada Dados.

  2. Na pasta Dados, crie um novo arquivo chamado PizzaContext.cs. Adicione o seguinte código ao arquivo vazio:

    using Microsoft.EntityFrameworkCore;
    using ContosoPizza.Models;
    
    namespace ContosoPizza.Data;
    
    public class PizzaContext : DbContext
    {
        public PizzaContext (DbContextOptions<PizzaContext> options)
            : base(options)
        {
        }
    
        public DbSet<Pizza> Pizzas => Set<Pizza>();
        public DbSet<Topping> Toppings => Set<Topping>();
        public DbSet<Sauce> Sauces => Set<Sauce>();
    }
    

    No código anterior:

    • O construtor aceita um parâmetro do tipo DbContextOptions<PizzaContext>. O construtor permite que o código externo passe na configuração para que o mesmo DbContext possa ser compartilhado entre o código de teste e produção, e até mesmo ser usado com diferentes provedores.
    • As DbSet<T> propriedades correspondem a tabelas a serem criadas no banco de dados.
    • Os nomes de tabela correspondem aos nomes de DbSet<T>PizzaContext propriedade na classe. Você pode substituir esse comportamento, se necessário.
    • Quando instanciado, PizzaContext expõe as Pizzaspropriedades , Toppingse Sauces . As alterações feitas nas coleções que essas propriedades expõem são propagadas para o banco de dados.
  3. No Program.cs, substitua // Add the PizzaContext pelo seguinte código:

    builder.Services.AddSqlite<PizzaContext>("Data Source=ContosoPizza.db");
    

    O código anterior:

    • Registra-se PizzaContext no sistema de injeção de dependência ASP.NET Core.
    • Especifica que PizzaContext usa o provedor de banco de dados SQLite.
    • Define uma cadeia de conexão SQLite que aponta para um arquivo local, ContosoPizza.db.

    Nota

    O SQLite usa arquivos de banco de dados locais, portanto, não há problema em codificar a cadeia de conexão. Para bancos de dados de rede como PostgreSQL e SQL Server, você sempre deve armazenar suas cadeias de conexão com segurança. Para o desenvolvimento local, use o Secret Manager. Para implantações de produção, considere usar um serviço como o Azure Key Vault.

  4. Também no Program.cs, substitua // Additional using declarations pelo código a seguir.

    using ContosoPizza.Data;
    

    Este código resolve dependências na etapa anterior.

  5. Guarde todas as alterações. O GitHub Codespaces salva suas alterações automaticamente.

  6. Crie o aplicativo no terminal executando dotnet build. A compilação deve ser bem-sucedida sem avisos ou erros.

Criar e executar uma migração

Em seguida, crie uma migração que você possa usar para criar seu banco de dados inicial.

  1. No escopo do terminal para a pasta do projeto ContosoPizza , execute o seguinte comando para gerar uma migração para criar as tabelas de banco de dados:

    dotnet ef migrations add InitialCreate --context PizzaContext
    

    No comando anterior:

    • A migração tem o nome: InitialCreate.
    • A opção --context especifica o nome da classe no projeto ContosoPizza, que deriva de DbContext.

    É apresentado um novo diretório Migrations na raiz do projeto ContosoPizza. O diretório contém um <timestamp>_InitialCreate.cs arquivo que descreve as alterações do banco de dados a serem traduzidas para um script de alteração DDL (Data Definition Language).

  2. Execute o seguinte comando para aplicar a migração InitialCreate:

    dotnet ef database update --context PizzaContext
    

    Este comando aplica a migração. ContosoPizza.db não existe, então este comando cria a migração no diretório do projeto.

    Gorjeta

    Todas as plataformas suportam a dotnet ef ferramenta. No Visual Studio no Windows, você pode usar os Add-Migration cmdlets e Update-Database PowerShell na janela integrada do Console do Gerenciador de Pacotes.

Inspecionar o banco de dados

O EF Core criou um banco de dados para seu aplicativo. Em seguida, vamos dar uma olhada dentro do banco de dados usando a extensão SQLite.

  1. No painel Explorer, clique com o botão direito do mouse no arquivo ContosoPizza.db e selecione Abrir Banco de Dados.

    Captura de tela que mostra a opção de menu Abrir Banco de Dados no painel Gerenciador de Códigos do Visual Studio.

    Uma pasta SQLite Explorer aparece no painel Explorer.

    Captura de tela que mostra a pasta SQLite Explorer no painel Explorer.

  2. Selecione a pasta SQLite Explorer para expandir o nó e todos os seus nós filho. Clique com o botão direito do mouse em ContosoPizza.db e selecione Mostrar Tabela 'sqlite_master' para exibir o esquema completo do banco de dados e as restrições que a migração criou.

    Captura de tela que mostra a pasta expandida do SQLite Explorer no painel Explorer.

    • Foram criadas tabelas que correspondem a cada entidade.
    • Os nomes das tabelas foram retirados dos nomes das DbSet propriedades no PizzaContext.
    • As propriedades nomeadas Id foram inferidas como sendo campos de chave primária de incremento automático.
    • As convenções de nomenclatura de chave primária e restrição de chave estrangeira do EF Core são PK_<primary key property> e FK_<dependent entity>_<principal entity>_<foreign key property>, respectivamente. Os marcadores de posição <dependent entity> e <principal entity> correspondem aos nomes das classes de entidades.

    Nota

    Como ASP.NET MVC Core, o EF Core usa uma abordagem de convenção sobre configuração . As convenções do EF Core reduzem o tempo de desenvolvimento ao inferirem a intenção do programador. Por exemplo, o núcleo do EF infere uma propriedade chamada Id ou <entity name>Id que seja a chave primária da tabela gerada. Se você optar por não adotar a convenção de nomenclatura, deverá anotar a propriedade com o [Key] atributo ou configurá-la como uma chave no OnModelCreating método do DbContext.

Alterar o modelo e atualizar o esquema do banco de dados

Seu gerente na Contoso Pizza fornece alguns novos requisitos, portanto, você precisa alterar seus modelos de entidade. Nas etapas a seguir, você modifica os modelos usando atributos de mapeamento (às vezes chamados de anotações de dados).

  1. Em Modelos\Pizza.cs, faça as seguintes alterações:

    1. Adicione uma using diretiva para System.ComponentModel.DataAnnotations.
    2. Adicione um [Required] atributo antes da Name propriedade para marcá-la como necessária.
    3. Adicione um [MaxLength(100)] atributo antes da Name propriedade para especificar um comprimento máximo de cadeia de caracteres de 100.

    Seu arquivo de Pizza.cs atualizado deve se parecer com o seguinte código:

    using System.ComponentModel.DataAnnotations;
    
    namespace ContosoPizza.Models;
    
    public class Pizza
    {
        public int Id { get; set; }
    
        [Required]
        [MaxLength(100)]
        public string? Name { get; set; }
    
        public Sauce? Sauce { get; set; }
    
        public ICollection<Topping>? Toppings { get; set; }
    }
    
  2. Em Modelos\Sauce.cs, faça as seguintes alterações:

    1. Adicione uma using diretiva para System.ComponentModel.DataAnnotations.
    2. Adicione um [Required] atributo antes da Name propriedade para marcá-la como necessária.
    3. Adicione um [MaxLength(100)] atributo antes da Name propriedade para especificar um comprimento máximo de cadeia de caracteres de 100.
    4. Adicione uma bool propriedade chamada IsVegan.

    Seu arquivo de Sauce.cs atualizado deve se parecer com o seguinte código:

    using System.ComponentModel.DataAnnotations;
    
    namespace ContosoPizza.Models;
    
    public class Sauce
    {
        public int Id { get; set; }
    
        [Required]
        [MaxLength(100)]
        public string? Name { get; set; }
    
        public bool IsVegan { get; set; }
    }
    
  3. Em Modelos\Topping.cs, faça as seguintes alterações:

    1. Adicionar using diretivas para System.ComponentModel.DataAnnotations e System.Text.Json.Serialization.

    2. Adicione um [Required] atributo antes da Name propriedade para marcá-la como necessária.

    3. Adicione um [MaxLength(100)] atributo antes da Name propriedade para especificar um comprimento máximo de cadeia de caracteres de 100.

    4. Adicione uma decimal propriedade com o nome Calories imediatamente após a Name propriedade.

    5. Adicione uma Pizzas propriedade do tipo ICollection<Pizza>?. Esta mudança cria Pizza-Topping uma relação muitos-para-muitos.

    6. Adicione um [JsonIgnore] atributo à Pizzas propriedade.

      Importante

      Esse atributo impede que Topping as entidades incluam a Pizzas propriedade quando o código da API da Web serializa a resposta para JSON. Sem essa alteração, uma coleção serializada de coberturas incluiria uma coleção de cada pizza que usa a cobertura. Cada pizza dessa coleção conteria uma coleção de coberturas, cada uma contendo novamente uma coleção de pizzas. Esse tipo de loop infinito é chamado de referência circular e não pode ser serializado.

    Seu arquivo de Topping.cs atualizado deve se parecer com o seguinte código:

    using System.ComponentModel.DataAnnotations;
    using System.Text.Json.Serialization;
    
    namespace ContosoPizza.Models;
    
    public class Topping
    {
        public int Id { get; set; }
    
        [Required]
        [MaxLength(100)]
        public string? Name { get; set; }
    
        public decimal Calories { get; set; }
    
        [JsonIgnore]
        public ICollection<Pizza>? Pizzas { get; set; }
    }
    
  4. Salve todas as suas alterações e execute dotnet build.

  5. Execute o seguinte comando para gerar uma migração para criar as tabelas de base de dados:

    dotnet ef migrations add ModelRevisions --context PizzaContext
    

    Este comando cria uma migração com o nome: ModelRevisions.

    Nota

    Você verá esta mensagem: Uma operação foi estruturada que pode resultar na perda de dados. Por favor, revise a migração para obter precisão. Essa mensagem apareceu porque você alterou a relação de Pizza um-para-muitos Topping para muitos, o que requer que uma coluna de chave estrangeira existente seja descartada. Como você ainda não tem nenhum dado em seu banco de dados, essa alteração não é problemática. No entanto, em geral, é uma boa ideia verificar a migração gerada quando esse aviso aparecer para garantir que a migração não exclua ou trunce nenhum dado.

  6. Execute o seguinte comando para aplicar a migração ModelRevisions:

    dotnet ef database update --context PizzaContext
    
  7. Na barra de título da pasta SQLite Explorer , selecione o botão Atualizar bancos de dados .

    Captura de tela que mostra o botão Atualizar bancos de dados na barra de título do SQLite Explorer.

  8. Na pasta SQLite Explorer, clique com o botão direito do mouse em ContosoPizza.db. Selecione Mostrar tabela 'sqlite_master' para visualizar o esquema e as restrições do banco de dados completo.

    Importante

    A extensão SQLite reutiliza guias SQLite abertas.

    • Uma PizzaTopping mesa de junção foi criada para representar a relação muitos-para-muitos entre pizzas e coberturas.
    • Novos campos foram adicionados a Toppings e Sauces.
      • Calories é definido como uma text coluna porque o SQLite não tem um tipo correspondente decimal .
      • Da mesma forma, IsVegan é definido como uma integer coluna. SQLite não define um bool tipo.
      • Em ambos os casos, o EF Core gerencia a tradução.
    • A Name coluna em cada tabela foi marcada not null, mas o SQLite não tem uma MaxLength restrição.

    Gorjeta

    Os provedores de banco de dados EF Core mapeiam um esquema de modelo para os recursos de um banco de dados específico. Embora o SQLite não implemente uma restrição correspondente para MaxLengtho , outros bancos de dados como SQL Server e PostgreSQL o fazem.

  9. Na pasta SQLite Explorer, clique com o botão direito do mouse na _EFMigrationsHistory tabela e selecione Mostrar tabela. A tabela contém uma lista de todas as migrações aplicadas ao banco de dados. Como você executou duas migrações, há duas entradas: uma para a migração InitialCreate e outra para ModelRevisions.

Nota

Este exercício usou atributos de mapeamento (anotações de dados) para mapear modelos para o banco de dados. Como alternativa ao mapeamento de atributos, você pode usar a API fluente do ModelBuilder para configurar modelos. Ambas as abordagens são válidas, mas alguns desenvolvedores preferem uma abordagem em detrimento da outra.

Você usou migrações para definir e atualizar um esquema de banco de dados. Na próxima unidade, você concluirá os métodos em PizzaService que manipular dados.

Verifique o seu conhecimento

1.

Numa classe de entidade, qual é a convenção de nomenclatura de propriedade para uma chave primária?