Partilhar via


Semear dados em um banco de dados usando .NET.NET Aspire

Neste artigo, aprende a configurar projetos .NET.NET Aspire para preencher dados numa base de dados durante o início da aplicação. .NET Aspire permite que você semeie dados usando scripts de banco de dados ou Entity Framework Core para plataformas comuns, como SQL Server, PostgreSQL e MySQL.

Quando semear dados

A semeadura de dados preenche previamente as tabelas de banco de dados com linhas de dados para que estejam prontas para testes por meio do seu aplicativo. Talvez você queira semear dados para os seguintes cenários:

  • Desenvolva e teste manualmente diferentes recursos do seu aplicativo em relação a um conjunto significativo de dados, como um catálogo de produtos ou uma lista de clientes.
  • Execute conjuntos de testes para verificar se os recursos se comportam de maneira específica com um determinado conjunto de dados.

Semeando dados manualmente é tedioso e demorado, então você deve automatizar o processo quando possível. Use volumes para executar scripts de banco de dados durante a inicialização de projetos .NET.NET Aspire. Você também pode semear seu banco de dados usando ferramentas como Entity Framework Core, que lida com muitas preocupações subjacentes para você.

Compreender os bancos de dados em contêineres

Por padrão, .NET.NET Aspire integrações de banco de dados dependem de bancos de dados em contêineres, que criam os seguintes desafios ao tentar semear dados:

  • .NET .NET Aspire destrói e recria contêineres sempre que o aplicativo é reiniciado, o que significa que, por padrão, você precisa semear novamente seu banco de dados toda vez que o aplicativo for reiniciado.
  • Dependendo da tecnologia de banco de dados selecionada, a nova instância de contêiner pode ou não criar um banco de dados padrão, o que significa que você também pode ter que criar o próprio banco de dados.
  • Mesmo que exista um banco de dados padrão, ele provavelmente não terá o nome ou esquema desejado para seu aplicativo específico.

.NET .NET Aspire permite resolver esses desafios usando volumes e algumas configurações para semear dados de forma eficaz.

Semear dados usando volumes e scripts SQL

Os volumes são a maneira recomendada de semear automaticamente bancos de dados em contêineres ao usar scripts SQL. Os volumes podem armazenar dados para vários contêineres ao mesmo tempo, oferecem alto desempenho e são fáceis de fazer backup ou migrar. Com .NET.NET Aspire, você configura um volume para cada contêiner de recursos usando o método ContainerResourceBuilderExtensions.WithBindMount, que aceita três parâmetros:

  • de origem: O caminho de origem da montagem do volume, que é o local físico no seu host.
  • Alvo: o caminho de destino no contentor dos dados que pretende persistir.

Considere o seguinte código de configuração de volume de um arquivo num projeto AppHost de exemplo :

var todosDbName = "Todos";
var todosDb = builder.AddPostgres("postgres")
    .WithEnvironment("POSTGRES_DB", todosDbName)
    .WithBindMount(
        "../DatabaseContainers.ApiService/data/postgres",
        "/docker-entrypoint-initdb.d")
    .AddDatabase(todosDbName);

Neste exemplo, os parâmetros do método .WithBindMount configuram o seguinte:

  • ../DatabaseContainers.ApiService/data/postgres define um caminho para o script SQL em seu projeto local que você deseja executar no contêiner para semear dados.
  • /docker-entrypoint-initdb.d define o caminho para um ponto de entrada no contêiner para que seu script seja executado durante a inicialização do contêiner.

O script SQL referenciado localizado em ../DatabaseContainers.ApiService/data/postgres cria e preenche a tabela Todos:

-- Postgres init script

-- Create the Todos table
CREATE TABLE IF NOT EXISTS Todos
(
    Id SERIAL PRIMARY KEY,
    Title text UNIQUE NOT NULL,
    IsComplete boolean NOT NULL DEFAULT false
);

-- Insert some sample data into the Todos table
INSERT INTO Todos (Title, IsComplete)
VALUES
    ('Give the dog a bath', false),
    ('Wash the dishes', false),
    ('Do the groceries', false)
ON CONFLICT DO NOTHING;

O script é executado durante a inicialização sempre que uma nova instância de contêiner é criada.

Exemplos de semeadura de banco de dados

Os exemplos a seguir demonstram como semear dados usando scripts SQL e configurações aplicadas usando o método .WithBindMount para diferentes tecnologias de banco de dados:

Observação

Visite o Aplicativo de Exemplo de Contêiner de Banco de Dados para exibir o projeto completo e a estrutura de arquivos de cada opção de banco de dados.

O código de configuração no . O arquivoProgram.cs AppHost monta os arquivos e pastas de banco de dados necessários e configura um ponto de entrada para que eles sejam executados durante a inicialização.

// SQL Server container is configured with an auto-generated password by default
// but doesn't support any auto-creation of databases or running scripts on startup so we have to do it manually.
var sqlserver = builder.AddSqlServer("sqlserver")
    // Mount the init scripts directory into the container.
    .WithBindMount("./sqlserverconfig", "/usr/config")
    // Mount the SQL scripts directory into the container so that the init scripts run.
    .WithBindMount("../DatabaseContainers.ApiService/data/sqlserver", "/docker-entrypoint-initdb.d")
    // Run the custom entrypoint script on startup.
    .WithEntrypoint("/usr/config/entrypoint.sh")
    // Configure the container to store data in a volume so that it persists across instances.
    .WithDataVolume()
    // Keep the container running between app host sessions.
    .WithLifetime(ContainerLifetime.Persistent);

O script entrypoint.sh está na pasta de projeto montada ./sqlserverconfig e é executado quando o contentor é iniciado. O script inicia SQL Server e verifica se está em execução.

#!/bin/bash

# Adapted from: https://github.com/microsoft/mssql-docker/blob/80e2a51d0eb1693f2de014fb26d4a414f5a5add5/linux/preview/examples/mssql-customize/entrypoint.sh

# Start the script to create the DB and user
/usr/config/configure-db.sh &

# Start SQL Server
/opt/mssql/bin/sqlservr

O script SQL init.sql que vive na pasta do projeto montada ../DatabaseContainers.ApiService/data/sqlserver cria a base de dados e as tabelas.

-- SQL Server init script

-- Create the AddressBook database
IF NOT EXISTS (SELECT * FROM sys.databases WHERE name = N'AddressBook')
BEGIN
  CREATE DATABASE AddressBook;
END;
GO

USE AddressBook;
GO

-- Create the Contacts table
IF OBJECT_ID(N'Contacts', N'U') IS NULL
BEGIN
    CREATE TABLE Contacts
    (
        Id        INT PRIMARY KEY IDENTITY(1,1) ,
        FirstName VARCHAR(255) NOT NULL,
        LastName  VARCHAR(255) NOT NULL,
        Email     VARCHAR(255) NULL,
        Phone     VARCHAR(255) NULL
    );
END;
GO

-- Ensure that either the Email or Phone column is populated
IF OBJECT_ID(N'chk_Contacts_Email_Phone', N'C') IS NULL
BEGIN
    ALTER TABLE Contacts
    ADD CONSTRAINT chk_Contacts_Email_Phone CHECK
    (
        Email IS NOT NULL OR Phone IS NOT NULL
    );
END;
GO

-- Insert some sample data into the Contacts table
IF (SELECT COUNT(*) FROM Contacts) = 0
BEGIN
    INSERT INTO Contacts (FirstName, LastName, Email, Phone)
    VALUES
        ('John', 'Doe', 'john.doe@example.com', '555-123-4567'),
        ('Jane', 'Doe', 'jane.doe@example.com', '555-234-5678');
END;
GO

Semear dados usando Entity Framework Core

Você também pode preencher dados nos projetos .NET Aspire executando explicitamente migrações durante a inicialização usando Entity Framework Core. Entity Framework Core lida com conexões de banco de dados subjacentes e criação de esquema para você, o que elimina a necessidade de usar volumes ou executar scripts SQL durante a inicialização do contêiner.

Importante

Esses tipos de configurações só devem ser feitos durante o desenvolvimento, portanto, certifique-se de adicionar uma condicional que verifique o contexto do ambiente atual.

Adicione o seguinte código ao arquivo Program.cs do seu projeto API Service .

// Register DbContext class
builder.AddSqlServerDbContext<TicketContext>("sqldata");

var app = builder.Build();

app.MapDefaultEndpoints();

if (app.Environment.IsDevelopment())
{
    // Retrieve an instance of the DbContext class and manually run migrations during startup
    using (var scope = app.Services.CreateScope())
    {
        var context = scope.ServiceProvider.GetRequiredService<TicketContext>();
        context.Database.Migrate();
    }
}

Próximos passos

A propagação de banco de dados é útil em vários cenários de desenvolvimento de aplicativos. Tente combinar essas técnicas com as implementações de recursos demonstradas nos tutoriais a seguir: