Použijte Entity Framework Core migrace v .NET Aspire
Vzhledem k tomu, že projekty .NET.NET Aspire používají kontejnerizovanou architekturu, databáze jsou dočasné a je možné je kdykoli znovu vytvořit. Entity Framework Core (EF Core) používá funkci označovanou jako migrace k vytváření a aktualizaci schémat databáze. Vzhledem k tomu, že se databáze po spuštění aplikace znovu vytvoří, musíte při každém spuštění aplikace použít migrace, abyste inicializovali schéma databáze. Toho dosáhnete tak, že ve své aplikaci zaregistrujete projekt služby migrace, který spouští migrace během spouštění.
V tomto kurzu se dozvíte, jak nakonfigurovat .NET Aspire projekty tak, aby spouštěly EF Core migrace během spouštění aplikace.
Požadavky
Pokud chcete pracovat s .NET.NET Aspire, potřebujete místně nainstalovat následující:
- .NET 8.0 nebo .NET 9.0
- Modul runtime kontejneru kompatibilní s OCI, například:
- Docker Desktop nebo Podman. Další informace najdete v tématu běhové prostředí kontejneru.
- Integrované vývojové prostředí (IDE) nebo editor kódu, například:
- Visual Studio 2022 verze 17.9 nebo novější (volitelné)
-
Visual Studio Code (volitelné)
- C# Dev Kit: Rozšíření (volitelné)
- JetBrains Rider s .NETpluginem.NET Aspire (volitelně)
Další informace najdete v tématu .NET.NET Aspire nastavení a nástrojea .NET.NET Aspire SDK.
Získání úvodní aplikace
Tento kurz používá ukázkovou aplikaci, která předvádí, jak aplikovat EF Core migrace v .NET Aspire. Pomocí Visual Studio naklonujte ukázkovou aplikaci z GitHub nebo použijte následující příkaz:
git clone https://github.com/MicrosoftDocs/aspire-docs-samples/
Ukázková aplikace je ve složce SupportTicketApi. Otevřete řešení v Visual Studio nebo VS Code a chvíli si prohlédněte ukázkovou aplikaci a před pokračováním se ujistěte, že se spustí. Ukázková aplikace je základní API pro podpůrné tikety a obsahuje následující projekty:
- SupportTicketApi.Api: Projekt ASP.NET Core, který je hostitelem rozhraní API.
- SupportTicketApi.Data: Obsahuje kontexty a modely EF Core.
- SupportTicketApi.AppHost: Obsahuje aplikační hostitel .NETa nastavení konfigurace.NET Aspire.
- SupportTicketApi.ServiceDefaults: Obsahuje výchozí konfigurace služby.
Spusťte aplikaci, abyste měli jistotu, že funguje podle očekávání. Na řídicím panelu .NET.NET Aspire vyberte koncový bod https Swagger a otestujte ho pomocí GET /api/SupportTickets rozbalením operace a výběrem možnosti Vyzkoušet. Kliknutím na Spustit odešlete požadavek a zobrazte odpověď.
[
{
"id": 1,
"title": "Initial Ticket",
"description": "Test ticket, please ignore."
}
]
Vytvořte migrace
Začněte vytvořením některých migrací, které se mají použít.
Otevřete terminál (Ctrl+` v Visual Studio).
Nastavte SupportTicketApiSupportTicketApi.Api jako aktuální adresář.
Pomocí nástroje příkazového řádku
dotnet ef
vytvořte novou migraci, která zachytí počáteční stav schématu databáze:dotnet ef migrations add InitialCreate --project ..\SupportTicketApi.Data\SupportTicketApi.Data.csproj
Příkaz pro pokračování:
- Spustí migrační nástroj příkazového řádku EF Core v adresáři SupportTicketApi.Api.
dotnet ef
se spouští v tomto umístění, protože služba API je místem, kde se používá kontext databáze. - Vytvoří migraci s názvem InitialCreate.
- Vytvoří migraci ve složce Migrations v projektu SupportTicketApi.Data.
- Spustí migrační nástroj příkazového řádku EF Core v adresáři SupportTicketApi.Api.
Upravte model tak, aby zahrnoval novou vlastnost. Otevřete SupportTicketApi.DataModelsSupportTicket.cs a přidejte novou vlastnost do třídy
SupportTicket
:public sealed class SupportTicket { public int Id { get; set; } [Required] public string Title { get; set; } = string.Empty; [Required] public string Description { get; set; } = string.Empty; public bool Completed { get; set; } }
Vytvořte další novou migraci, která zachytí změny modelu:
dotnet ef migrations add AddCompleted --project ..\SupportTicketApi.Data\SupportTicketApi.Data.csproj
Teď máte nějaké migrace, které musíte aplikovat. V dalším kroku vytvoříte službu migrace, která tyto migrace použije při spuštění aplikace.
Vytvoření služby migrace
Pokud chcete spustit migrace při spuštění, musíte vytvořit službu, která migraci použije.
Přidejte do řešení nový projekt Worker Service. Pokud používáte Visual Studio, klikněte pravým tlačítkem na řešení v Průzkumníku řešení a vyberte Add>New Project. Vyberte Worker Service a pojmenujte projekt SupportTicketApi.MigrationService. Pokud používáte příkazový řádek, použijte následující příkazy z adresáře řešení:
dotnet new worker -n SupportTicketApi.MigrationService dotnet sln add SupportTicketApi.MigrationService
Pomocí SupportTicketApi.Data nebo příkazového řádku přidejte do projektu SupportTicketApi.ServiceDefaults odkazy na SupportTicketApi.MigrationService a Visual Studio projektu:
dotnet add SupportTicketApi.MigrationService reference SupportTicketApi.Data dotnet add SupportTicketApi.MigrationService reference SupportTicketApi.ServiceDefaults
Přidejte 📦Aspire. Odkaz na balíček NuGet microsoft.EntityFrameworkCore.SqlServer odkaz na projekt SupportTicketApi.MigrationService pomocí Visual Studio nebo příkazového řádku:
dotnet add package Aspire.Microsoft.EntityFrameworkCore.SqlServer
Přidejte zvýrazněné řádky do souboru Program.cs v projektu SupportTicketApi.MigrationService:
using SupportTicketApi.Data.Contexts; using SupportTicketApi.MigrationService; var builder = Host.CreateApplicationBuilder(args); builder.AddServiceDefaults(); builder.Services.AddHostedService<Worker>(); builder.Services.AddOpenTelemetry() .WithTracing(tracing => tracing.AddSource(Worker.ActivitySourceName)); builder.AddSqlServerDbContext<TicketContext>("sqldata"); var host = builder.Build(); host.Run();
V předchozím kódu:
- Metoda rozšíření
AddServiceDefaults
přidává výchozí funkce služby. - Metoda rozšíření
AddOpenTelemetry
konfiguruje funkčnost OpenTelemetry. - Metoda rozšíření
AddSqlServerDbContext
přidá službuTicketContext
do kolekce služeb. Tato služba se používá ke spouštění migrací a naplnění databáze počátečními daty.
- Metoda rozšíření
Obsah souboru Worker.cs v projektu SupportTicketApi.MigrationService nahraďte následujícím kódem:
using System.Diagnostics; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Storage; using OpenTelemetry.Trace; using SupportTicketApi.Data.Contexts; using SupportTicketApi.Data.Models; namespace SupportTicketApi.MigrationService; public class Worker( IServiceProvider serviceProvider, IHostApplicationLifetime hostApplicationLifetime) : BackgroundService { public const string ActivitySourceName = "Migrations"; private static readonly ActivitySource s_activitySource = new(ActivitySourceName); protected override async Task ExecuteAsync(CancellationToken cancellationToken) { using var activity = s_activitySource.StartActivity("Migrating database", ActivityKind.Client); try { using var scope = serviceProvider.CreateScope(); var dbContext = scope.ServiceProvider.GetRequiredService<TicketContext>(); await EnsureDatabaseAsync(dbContext, cancellationToken); await RunMigrationAsync(dbContext, cancellationToken); await SeedDataAsync(dbContext, cancellationToken); } catch (Exception ex) { activity?.RecordException(ex); throw; } hostApplicationLifetime.StopApplication(); } private static async Task EnsureDatabaseAsync(TicketContext dbContext, CancellationToken cancellationToken) { var dbCreator = dbContext.GetService<IRelationalDatabaseCreator>(); var strategy = dbContext.Database.CreateExecutionStrategy(); await strategy.ExecuteAsync(async () => { // Create the database if it does not exist. // Do this first so there is then a database to start a transaction against. if (!await dbCreator.ExistsAsync(cancellationToken)) { await dbCreator.CreateAsync(cancellationToken); } }); } private static async Task RunMigrationAsync(TicketContext dbContext, CancellationToken cancellationToken) { var strategy = dbContext.Database.CreateExecutionStrategy(); await strategy.ExecuteAsync(async () => { // Run migration in a transaction to avoid partial migration if it fails. await using var transaction = await dbContext.Database.BeginTransactionAsync(cancellationToken); await dbContext.Database.MigrateAsync(cancellationToken); await transaction.CommitAsync(cancellationToken); }); } private static async Task SeedDataAsync(TicketContext dbContext, CancellationToken cancellationToken) { SupportTicket firstTicket = new() { Title = "Test Ticket", Description = "Default ticket, please ignore!", Completed = true }; var strategy = dbContext.Database.CreateExecutionStrategy(); await strategy.ExecuteAsync(async () => { // Seed the database await using var transaction = await dbContext.Database.BeginTransactionAsync(cancellationToken); await dbContext.Tickets.AddAsync(firstTicket, cancellationToken); await dbContext.SaveChangesAsync(cancellationToken); await transaction.CommitAsync(cancellationToken); }); } }
V předchozím kódu:
- Metoda
ExecuteAsync
je volána při spuštění pracovního procesu. Následně provede následující kroky:- Získá odkaz na službu
TicketContext
od poskytovatele služeb. - Zavolá
EnsureDatabaseAsync
pro vytvoření databáze, pokud neexistuje. - Volá
RunMigrationAsync
, aby se použily všechny čekající migrace. - Aby databáze byla naplněna počátečními daty, je volána funkce
SeedDataAsync
. - Zastaví pracovníka pomocí
StopApplication
.
- Získá odkaz na službu
- Metody
EnsureDatabaseAsync
,RunMigrationAsync
aSeedDataAsync
všechny zapouzdřují příslušné databázové operace pomocí strategií provádění ke zpracování přechodných chyb, ke kterým může dojít při interakci s databází. Další informace o strategiích provádění najdete v tématu Odolnost připojení.
- Metoda
Přidání služby migrace do orchestrátoru
Služba migrace se vytvoří, ale je potřeba ji přidat do hostitele aplikace .NET.NET Aspire, aby se spustila při spuštění aplikace.
V projektu SupportTicketApi.AppHost otevřete soubor Program.cs.
Do metody
ConfigureServices
přidejte následující zvýrazněný kód:var builder = DistributedApplication.CreateBuilder(args); var sql = builder.AddSqlServer("sql") .AddDatabase("sqldata"); builder.AddProject<Projects.SupportTicketApi_Api>("api") .WithReference(sql); builder.AddProject<Projects.SupportTicketApi_MigrationService>("migrations") .WithReference(sql); builder.Build().Run();
Tím se projekt SupportTicketApi.MigrationService začlení jako služba v aplikaci hostitele .NET.NET Aspire.
Důležitý
Pokud používáte Visual Studioa při vytváření projektu Enlist in Aspire orchestration jste vybrali možnost Worker Service, přidá se podobný kód automaticky s názvem služby
supportticketapi-migrationservice
. Nahraďte tento kód předchozím kódem.
Odebrání existujícího počátečního kódu
Protože služba migrace naplní databázi, měli byste z projektu rozhraní API odebrat stávající kód pro naplnění dat.
V projektu SupportTicketApi.Api otevřete soubor Program.cs.
Odstraňte zvýrazněné čáry.
if (app.Environment.IsDevelopment()) { app.UseSwagger(); app.UseSwaggerUI(); using (var scope = app.Services.CreateScope()) { var context = scope.ServiceProvider.GetRequiredService<TicketContext>(); context.Database.EnsureCreated(); if(!context.Tickets.Any()) { context.Tickets.Add(new SupportTicket { Title = "Initial Ticket", Description = "Test ticket, please ignore." }); context.SaveChanges(); } } }
Testování služby migrace
Teď, když je služba migrace nakonfigurovaná, spusťte aplikaci a otestujte migrace.
Spusťte aplikaci a sledujte řídicí panel SupportTicketApi.
Po krátkém čekání bude stav služby
migrations
zobrazen jako Dokončeno.Vyberte odkaz View ve službě migrace a prozkoumejte protokoly zobrazující provedené SQL příkazy.
Získání kódu
Na
Další ukázkový kód
Ukázková aplikace Aspire Shop používá tento přístup pro aplikaci migrací. Podívejte se na projekt AspireShop.CatalogDbManager
pro implementaci služby migrace.