Exercício – Configurar uma migração

Concluído

Nesta unidade, vai criar classes de entidade C# que serão mapeadas para tabelas numa base de dados SQLite local. A funcionalidade migrações do EF Core produz tabelas dessas entidades.

Uma migração fornece uma forma de atualizar incrementalmente o esquema da base de dados.

Obter os ficheiros do projeto

Para começar, obtenha os ficheiros do projeto. Tem algumas opções para obter os ficheiros do projeto:

  • Utilizar o GitHub Codespaces
  • Clonar o repositório do GitHub

Se tiver um runtime de contentor compatível instalado, também pode utilizar a extensão Dev Containers para abrir o repositório num contentor com as ferramentas pré-instaladas.

Utilizar o GitHub Codespaces

Um espaço de código é um IDE alojado na cloud. Se estiver a utilizar o GitHub Codespaces, aceda ao repositório no seu browser. Selecione Código e, em seguida, crie um novo espaço de código no main ramo .

Clonar o repositório do GitHub

Se não estiver a utilizar o GitHub Codespaces, pode clonar o repositório do GitHub do projeto e, em seguida, abrir os ficheiros como uma pasta no Visual Studio Code.

  1. Abra um terminal de comandos e, em seguida, clone o projeto a partir do GitHub com a linha de comandos:

    git clone https://github.com/MicrosoftDocs/mslearn-persist-data-ef-core
    
  2. Aceda à 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 tem os ficheiros do projeto com os quais trabalhar. Veja o que está no projeto e reveja o código.

  • O projeto, uma API Web ASP.NET Core, está localizado no diretório ContosoPizza. Os caminhos de ficheiro referidos neste módulo são relativos ao diretório ContosoPizza .
  • Services/PizzaService.cs é uma classe de serviço que define métodos CRUD (criar, ler, atualizar e eliminar). Todos os métodos atualmente lançam System.NotImplementedException.
  • Em Program.cs, PizzaService está registado no sistema de injeção de dependências ASP.NET Core.
  • Controllers/PizzaController.cs é um valor que ApiController expõe um ponto final para verbos HTTP POST, GET, PUT e DELETE. Estes verbos chamam os métodos CRUD correspondentes em PizzaService. PizzaService é injetado no PizzaController construtor.
  • A pasta Modelos contém os modelos que são utilizados por PizzaService e PizzaController.
  • Os modelos de entidades , 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 a aplicação no Visual Studio Code:

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

    É aberto um painel de terminal no âmbito do diretório ContosoPizza .

  2. Crie a aplicação com o seguinte comando:

    dotnet build
    

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

Adicionar pacotes NuGet e ferramentas EF Core

O motor de base de dados com o qual trabalha neste módulo é o SQLite. O SQLite é um motor de base de dados leve e baseado em ficheiros. É uma boa opção para desenvolvimento e teste e também é uma boa opção para implementações de produção em pequena escala.

Nota

Conforme mencionado anteriormente, os fornecedores de bases de dados no EF Core são plug-able. O SQLite é uma boa opção para este módulo, uma vez que é simples e multiplataforma. Pode utilizar o mesmo código para trabalhar com diferentes motores de base de dados, como SQL Server e PostgreSQL. Pode até utilizar vários motores de base de dados na mesma aplicação.

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 fornecedor de base de dados SQLite EF Core e todas as respetivas dependências, incluindo os serviços comuns do EF Core.

  2. Execute este comando:

    dotnet add package Microsoft.EntityFrameworkCore.Design
    

    Este comando adiciona pacotes necessários para as ferramentas do EF Core.

  3. Para concluir, execute este comando:

    dotnet tool install --global dotnet-ef
    

    Este comando instala dotnet ef, a ferramenta que irá utilizar para criar migrações e andaimes.

    Dica

    Se dotnet ef já estiver instalado, pode atualizá-lo ao executar dotnet tool update --global dotnet-ef.

Estruturar modelos e DbContext

Agora, vai adicionar e configurar uma DbContext implementação. DbContext é um gateway através do qual pode interagir com a base de dados.

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

  2. Na pasta Dados , crie um novo ficheiro com o nome PizzaContext.cs. Adicione o seguinte código ao ficheiro 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 partilhado entre código de teste e de produção e até mesmo ser utilizado com diferentes fornecedores.
    • As DbSet<T> propriedades correspondem às tabelas a criar na base de dados.
    • Os nomes das tabelas corresponderão aos nomes das propriedades DbSet<T> na classe PizzaContext. Se necessário, pode substituir este comportamento.
    • Quando instanciado, PizzaContext expõe Pizzasas propriedades , Toppingse Sauces . As alterações efetuadas às coleções expostas por essas propriedades serão propagadas para a base de dados.
  3. Em Program.cs, substitua // Add the PizzaContext pelo seguinte código:

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

    O código anterior:

    • Regista-se no sistema de injeção de dependências PizzaContext ASP.NET Core.
    • Especifica que PizzaContext irá utilizar o fornecedor de base de dados SQLite.
    • Define uma cadeia de ligação SQLite que aponta para um ficheiro local, ContosoPizza.db.

    Nota

    O SQLite utiliza ficheiros de base de dados locais, pelo que provavelmente não há problema em codificar a cadeia de ligação. Para bases de dados de rede como PostgreSQL e SQL Server, deve sempre armazenar as cadeias de ligação de forma segura. Para desenvolvimento local, utilize o Gestor de Segredos. Para implementações de produção, considere utilizar um serviço como o Azure Key Vault.

  4. Também em Program.cs, substitua // Additional using declarations pelo seguinte código.

    using ContosoPizza.Data;
    

    Este código resolve as dependências no passo anterior.

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

  6. Crie a aplicação no terminal ao executar 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 pode utilizar para criar a sua base de dados inicial.

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

    dotnet ef migrations add InitialCreate --context PizzaContext
    

    No comando anterior:

    • É dado o nome InitialCreate à migração.
    • 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 ficheiro que descreve as alterações da base de dados a traduzir para um script de alteração da Linguagem de Definição de Dados (DDL).

  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, pelo que a migração é criada no diretório do projeto.

    Dica

    A ferramenta dotnet ef é suportada em todas as plataformas. No Visual Studio no Windows, pode utilizar os cmdlets e Update-Database do Add-Migration PowerShell na janela da Consola integrada do Gestor de Pacotes.

Inspecionar a base de dados

O EF Core criou uma base de dados para a sua aplicação. Em seguida, veja dentro da base de dados com a extensão SQLite.

  1. No painel Explorador , clique com o botão direito do rato no ficheiro ContosoPizza.db e selecione Abrir Base de Dados.

    Captura de ecrã a mostrar a opção de menu Abrir Base de Dados no painel Explorador do Visual Studio Code.

    É apresentada uma pasta do Explorador do SQLite no painel Explorador .

    Captura de ecrã a mostrar a pasta Explorador do SQLite no painel Explorador.

  2. Selecione a pasta EXPLORADOR DO SQLite para expandir o nó e todos os nós subordinados. Clique com o botão direito do rato em ContosoPizza.db e selecione Mostrar Tabela 'sqlite_master' para ver o esquema completo da base de dados e as restrições que a migração criou.

    Captura de ecrã que mostra a pasta expandida do EXPLORADOR do SQLite no painel Explorador.

    • 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 estando a criar automaticamente campos de chave primária.
    • As convenções de nomenclatura de chave primária e de restrição de chave externa do EF Core são PK_<primary key property> e FK_<dependent entity>_<principal entity>_<foreign key property>, respetivamente. Os marcadores de posição <dependent entity> e <principal entity> correspondem aos nomes das classes de entidades.

    Nota

    Tal como ASP.NET Core MVC, o EF Core utiliza uma convenção sobre a abordagem de configuração. As convenções do EF Core reduzem o tempo de desenvolvimento ao inferirem a intenção do programador. Por exemplo, uma propriedade com o nome Id ou <entity name>Id é inferida para ser a chave primária da tabela gerada. Se optar por não adotar a convenção de nomenclatura, a propriedade tem de ser anotada com o [Key] atributo ou configurada como uma chave no OnModelCreating método do DbContext.

Alterar o modelo e atualizar o esquema da base de dados

O seu gestor na Contoso Pizza fornece-lhe alguns requisitos novos, pelo que tem de alterar os modelos de entidade. Nos passos seguintes, pode modificar os modelos com atributos de mapeamento (por vezes denominados anotações de dados).

  1. Em Models\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 marcar a propriedade como necessária.
    3. Adicione um [MaxLength(100)] atributo antes da Name propriedade para especificar um comprimento de cadeia máximo de 100.
    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 Models\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 marcar a propriedade como necessária.
    3. Adicione um [MaxLength(100)] atributo antes da Name propriedade para especificar um comprimento de cadeia máximo de 100.
    4. Adicione uma bool propriedade com o nome IsVegan.
    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 Models\Topping.cs, faça as seguintes alterações:

    1. Adicione using diretivas para System.ComponentModel.DataAnnotations e System.Text.Json.Serialization.
    2. Adicione um [Required] atributo antes da Name propriedade para marcar a propriedade como necessária.
    3. Adicione um [MaxLength(100)] atributo antes da Name propriedade para especificar um comprimento de cadeia máximo 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>? para criar Pizza-Topping uma relação muitos-para-muitos.
    6. Adicione um [JsonIgnore] atributo à Pizzas propriedade .

    Importante

    Estes passos impedem Topping que as entidades incluíssem a Pizzas propriedade quando o código da API Web serializa a resposta ao JSON. Sem esta alteração, uma coleção serializada de coberturas incluiria uma coleção de cada pizza que usa a cobertura. Cada pizza nessa coleção conteria uma coleção de coberturas, que cada uma novamente conteria uma coleção de pizzas. Este tipo de ciclo infinito é denominado referência circular e não pode ser serializado.

    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. Guarde todas as 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
    

    É criada uma migração com o nome ModelRevisions .

    Nota

    Esta mensagem é apresentada: foi estruturada uma operação que pode resultar na perda de dados. Reveja a migração para obter precisão. A mensagem é apresentada porque alterou a relação de Pizza um Topping para muitos para muitos, o que requer que uma coluna de chave externa existente seja removida. Uma vez que ainda não tem dados na base de dados, esta alteração não é problemática. No entanto, em geral, é aconselhável verificar a migração gerada quando este aviso aparecer para garantir que não existem dados eliminados ou truncados pela migração.

  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 Bases de Dados .

    Captura de ecrã que mostra o botão Atualizar Bases de Dados na barra de título do EXPLORADOR DO SQLite.

  8. Na pasta EXPLORADOR DO SQLite , clique com o botão direito do rato em ContosoPizza.db. Selecione Mostrar Tabela "sqlite_master" para ver o esquema e as restrições completos da base de dados.

    Importante

    A extensão SQLite reutiliza os separadores SQLite abertos.

    • Foi criada uma PizzaTopping tabela de associação para representar a relação muitos-para-muitos entre pizzas e coberturas.
    • Foram adicionados novos campos 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. O SQLite não define um bool tipo.
      • Em ambos os casos, o EF Core gere a tradução.
    • A Name coluna em cada tabela foi marcada not null, mas o SQLite não tem uma MaxLength restrição.

    Dica

    Os fornecedores de bases de dados EF Core mapeiam um esquema de modelo para as funcionalidades de uma base de dados específica. Embora o SQLite não implemente uma restrição correspondente para MaxLengtho , outras bases de dados, como SQL Server e PostgreSQL, sim.

  9. Na pasta EXPLORADOR DO SQLite , clique com o botão direito do rato na _EFMigrationsHistory tabela e selecione Mostrar Tabela. A tabela contém uma lista de todas as migrações que são aplicadas à base de dados. Uma vez que executou duas migrações, existem duas entradas: uma para a migração InitialCreate e outra para ModelRevisions.

Nota

Este exercício utilizou atributos de mapeamento (anotações de dados) para mapear modelos para a base de dados. Como alternativa aos atributos de mapeamento, pode utilizar a API Fluent do ModelBuilder para configurar modelos. Ambas as abordagens são válidas, mas alguns programadores preferem uma abordagem em vez da outra.

Utilizou migrações para definir e atualizar um esquema de base de dados. Na próxima unidade, irá concluir os métodos nessa PizzaService manipulação de dados.

Verifique o seu conhecimento

1.

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