Condividi tramite


Inizializzare i dati in un database usando .NET.NET Aspire

In questo articolo, impari come configurare i progetti .NET.NET Aspire per inizializzare i dati in un database all'avvio dell'app. .NET Aspire consente di eseguire il seeding dei dati usando script di database o Entity Framework Core per piattaforme comuni, ad esempio SQL Server, PostgreSQL e MySQL.

Quando inizializzare i dati

Il seeding dei dati prepopola le tabelle di database con righe di dati in modo che siano pronte per il test tramite l'app. È possibile eseguire il seeding dei dati per gli scenari seguenti:

  • Sviluppare e testare manualmente diverse funzionalità dell'app rispetto a un set significativo di dati, ad esempio un catalogo di prodotti o un elenco di clienti.
  • Eseguire gruppi di test per verificare che le funzionalità si comportino in modo specifico con un determinato set di dati.

Il seeding manuale dei dati è noioso e richiede molto tempo, quindi è consigliabile automatizzare il processo quando possibile. Usare i volumi per eseguire script di database per i progetti .NET.NET Aspire durante l'avvio. È anche possibile eseguire il seeding del database usando strumenti come Entity Framework Core, che gestisce molti problemi sottostanti.

Comprendere i database containerizzati

Per impostazione predefinita, le integrazioni di database .NET.NET Aspire si basano su database containerizzati, che creano le seguenti sfide quando si tenta di popolare i dati:

  • .NET .NET Aspire distrugge e ricrea i contenitori ogni volta che l'app viene riavviata, il che significa che per impostazione predefinita è necessario eseguire nuovamente il seeding del database ogni volta che l'app viene riavviata.
  • A seconda della tecnologia di database selezionata, la nuova istanza del contenitore potrebbe creare o meno un database predefinito, il che significa che potrebbe anche essere necessario creare il database stesso.
  • Anche se esiste un database predefinito, probabilmente non avrà il nome o lo schema desiderato per l'app specifica.

.NET .NET Aspire consente di risolvere questi problemi usando volumi e alcune configurazioni per eseguire il seeding dei dati in modo efficace.

Eseguire il seeding dei dati usando volumi e script SQL

I volumi sono il modo consigliato per inizializzare automaticamente i database in contenitori quando si usano script SQL. I volumi possono archiviare i dati per più contenitori alla volta, offrire prestazioni elevate e semplificare il backup o la migrazione. Con .NET.NET Aspireè possibile configurare un volume per ogni contenitore di risorse usando il metodo ContainerResourceBuilderExtensions.WithBindMount, che accetta tre parametri:

  • Origine: il percorso sorgente per il montaggio del volume, ovvero la posizione fisica sul tuo host.
  • Target: Il percorso di destinazione nel contenitore dei dati che si desidera rendere persistenti.

Si consideri il seguente codice di configurazione del volume da un file di in un progetto di AppHost di esempio :

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

In questo esempio i parametri del metodo .WithBindMount configurano quanto segue:

  • ../DatabaseContainers.ApiService/data/postgres imposta un percorso dello script SQL nel tuo progetto locale da eseguire nel contenitore per popolare i dati.
  • /docker-entrypoint-initdb.d imposta il percorso di un punto di ingresso nel contenitore in modo che lo script venga eseguito durante l'avvio del contenitore.

Lo script SQL a cui si fa riferimento si trova in ../DatabaseContainers.ApiService/data/postgres crea e esegue il seeding di una tabella 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;

Lo script viene eseguito durante l'avvio ogni volta che viene creata una nuova istanza del contenitore.

Esempi di 'seeding' del database

Gli esempi seguenti illustrano come eseguire il seeding dei dati usando script e configurazioni SQL applicati usando il metodo .WithBindMount per tecnologie di database diverse:

Nota

Per visualizzare il progetto completo e la struttura dei file per ogni opzione di database, visitare l'app di esempio del contenitore di database .

Codice di configurazione nel . AppHostProgram.cs file monta i file e le cartelle di database necessari e configura un punto di ingresso in modo che vengano eseguiti durante l'avvio.

// 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);

Lo script entrypoint.sh si trova nella cartella del progetto ./sqlserverconfig montata e viene eseguito all'avvio del contenitore. Lo script avvia SQL Server e verifica che sia in esecuzione.

#!/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

Lo script SQL init.sql presente nella cartella del progetto ../DatabaseContainers.ApiService/data/sqlserver montata crea il database e le tabelle.

-- 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

Inizializzare i dati usando Entity Framework Core

È anche possibile inizializzare i dati nei progetti .NET Aspire usando Entity Framework Core eseguendo esplicitamente le migrazioni all'avvio. Entity Framework Core gestisce automaticamente le connessioni di database sottostanti e la creazione dello schema, eliminando la necessità di usare volumi o eseguire script SQL durante l'avvio del contenitore.

Importante

Questi tipi di configurazioni devono essere eseguiti solo durante lo sviluppo, quindi assicurati di aggiungere una condizione che verifichi il contesto dell'ambiente corrente.

Aggiungere il codice seguente al file del progetto del servizio API .

// 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();
    }
}

Passaggi successivi

Il seeding del database è utile in diversi scenari di sviluppo di app. Provare a combinare queste tecniche con le implementazioni delle risorse illustrate nelle esercitazioni seguenti: