Pas migraties van Entity Framework Core toe in .NET Aspire
Aangezien .NET.NET Aspire projecten een containerarchitectuur gebruiken, zijn databases kortstondig en kunnen ze op elk gewenst moment opnieuw worden gemaakt. Entity Framework Core (EF Core) maakt gebruik van een functie met de naam migraties voor het maken en bijwerken van databaseschema's. Omdat databases opnieuw worden gemaakt wanneer de app wordt gestart, moet u migraties toepassen om het databaseschema te initialiseren telkens wanneer uw app wordt gestart. Dit wordt bereikt door een migratieserviceproject te registreren in uw app die migraties uitvoert tijdens het opstarten.
In deze zelfstudie leert u hoe u .NET Aspire projecten configureert om EF Core migraties uit te voeren tijdens het opstarten van de app.
Voorwaarden
Als u met .NET.NET Aspirewilt werken, hebt u het volgende lokaal geïnstalleerd:
- .NET 8,0 of .NET 9,0
- Een OCI-compatibele containerruntime, zoals:
- Docker Desktop of Podman. Zie Container Runtime-voor meer informatie.
- Een IDE (Integrated Developer Environment) of code-editor, zoals:
- Visual Studio 2022 versie 17.9 of hoger (optioneel)
-
Visual Studio Code (optioneel)
- C# Dev Kit: extensie- (optioneel)
- JetBrains Rider met .NET.NET Aspire plugin (optioneel)
Zie .NET.NET Aspire setup en hulpprogramma'sen .NET.NET Aspire SDK-voor meer informatie.
De starter-app verkrijgen
In deze handleiding wordt een voorbeeldapp gebruikt om te laten zien hoe u EF Core-migraties in .NET Aspirekunt toepassen. Gebruik Visual Studio om de voorbeeld-app te klonen vanuit GitHub of gebruik de volgende opdracht:
git clone https://github.com/MicrosoftDocs/aspire-docs-samples/
De voorbeeld-app bevindt zich in de map SupportTicketApi. Open de oplossing in Visual Studio of VS Code en neem even de tijd om de voorbeeld-app te controleren en ervoor te zorgen dat deze wordt uitgevoerd voordat u doorgaat. De voorbeeld-app is een elementaire ondersteuningsticket-API en bevat de volgende projecten:
- SupportTicketApi.Api: het ASP.NET Core project dat als host fungeert voor de API.
- SupportTicketApi.Data: bevat de EF Core contexten en modellen.
- SupportTicketApi.AppHost: bevat de .NET.NET Aspire app-host en -configuratie.
- SupportTicketApi.ServiceDefaults: bevat de standaardserviceconfiguraties.
Voer de app uit om ervoor te zorgen dat deze werkt zoals verwacht. Selecteer in het .NET.NET Aspire-dashboard het https Swagger-eindpunt en test het GET /api/SupportTickets-eindpunt van de API door de bewerking uit te vouwen en uitproberente selecteren. Selecteer uitvoeren om de aanvraag te verzenden en het antwoord weer te geven:
[
{
"id": 1,
"title": "Initial Ticket",
"description": "Test ticket, please ignore."
}
]
Migraties maken
Begin met het maken van enkele migraties die u wilt toepassen.
Een terminal openen (Ctrl-+` in Visual Studio).
Stel SupportTicketApiSupportTicketApi.Api in als de huidige map.
Gebruik het
dotnet ef
opdrachtregelprogramma om een nieuwe migratie te maken om de initiële status van het databaseschema vast te leggen:dotnet ef migrations add InitialCreate --project ..\SupportTicketApi.Data\SupportTicketApi.Data.csproj
De volgende opdracht:
- Voert migratie-opdrachtregelprogramma EF Core uit in de map SupportTicketApi.Api.
dotnet ef
wordt uitgevoerd op deze locatie omdat de API-service de db-context gebruikt. - Hiermee maakt u een migratie met de naam InitialCreate.
- Hiermee maakt u de migratie in de map Migrations in het project SupportTicketApi.Data.
- Voert migratie-opdrachtregelprogramma EF Core uit in de map SupportTicketApi.Api.
Wijzig het model zodat het een nieuwe eigenschap bevat. Open SupportTicketApi.DataModelsSupportTicket.cs en voeg een nieuwe eigenschap toe aan de klasse
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; } }
Maak nog een nieuwe migratie om de wijzigingen in het model vast te leggen:
dotnet ef migrations add AddCompleted --project ..\SupportTicketApi.Data\SupportTicketApi.Data.csproj
U hebt nu enkele migraties die moeten worden toegepast. Vervolgens maakt u een migratieservice die deze migraties toepast tijdens het opstarten van de app.
De migratieservice maken
Als u de migraties bij het opstarten wilt uitvoeren, moet u een service maken die de migraties toepast.
Voeg een nieuw Worker Service project toe aan de oplossing. Als u Visual Studiogebruikt, klikt u met de rechtermuisknop op de oplossing in Solution Explorer en selecteert u Add>New Project. Selecteer Worker Service en geef het project een naam SupportTicketApi.MigrationService. Als u de opdrachtregel gebruikt, gebruikt u de volgende opdrachten uit de oplossingsmap:
dotnet new worker -n SupportTicketApi.MigrationService dotnet sln add SupportTicketApi.MigrationService
Voeg de SupportTicketApi.Data en SupportTicketApi.ServiceDefaults projectverwijzingen toe aan het SupportTicketApi.MigrationService project met behulp van Visual Studio of de opdrachtregel:
dotnet add SupportTicketApi.MigrationService reference SupportTicketApi.Data dotnet add SupportTicketApi.MigrationService reference SupportTicketApi.ServiceDefaults
Voeg de 📦Aspiretoe. Microsoft.EntityFrameworkCore.SqlServer NuGet-pakketreferentie naar het SupportTicketApi.MigrationService project met behulp van Visual Studio of de opdrachtregel:
dotnet add package Aspire.Microsoft.EntityFrameworkCore.SqlServer
Voeg de gemarkeerde regels toe aan het Program.cs-bestand in het SupportTicketApi.MigrationService project:
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();
In de voorgaande code:
- De
AddServiceDefaults
-extensiemethode voegt de standaardfunctionaliteit van de service toe. - De
AddOpenTelemetry
-extensiemethode configureert OpenTelemetry-functionaliteit. - De
AddSqlServerDbContext
-extensiemethode voegt deTicketContext
-service toe aan de serviceverzameling. Deze service wordt gebruikt om migraties uit te voeren en de database te seeden.
- De
Vervang de inhoud van het Worker.cs-bestand in het SupportTicketApi.MigrationService project door de volgende code:
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); }); } }
In de voorgaande code:
- De methode
ExecuteAsync
wordt aangeroepen wanneer de werker wordt gestart. Op zijn beurt worden de volgende stappen uitgevoerd:- Hiermee haalt u een referentie op naar de
TicketContext
-service van deze serviceprovider. - Roept
EnsureDatabaseAsync
aan om de database te maken als deze niet bestaat. - Roept
RunMigrationAsync
aan om alle openstaande migraties toe te passen. - Roept
SeedDataAsync
aan om de database te seeden met initiële gegevens. - Stopt de werknemer met
StopApplication
.
- Hiermee haalt u een referentie op naar de
- De
EnsureDatabaseAsync
,RunMigrationAsync
enSeedDataAsync
methoden bevatten allemaal hun respectieve databasebewerkingen met behulp van uitvoeringsstrategieën voor het afhandelen van tijdelijke fouten die kunnen optreden bij interactie met de database. Zie Verbindingstolerantievoor meer informatie over uitvoeringsstrategieën.
- De methode
De migratieservice toevoegen aan de orchestrator
De migratieservice wordt gemaakt, maar moet worden toegevoegd aan de .NET.NET Aspire app-host, zodat deze wordt uitgevoerd wanneer de app wordt gestart.
Open in het SupportTicketApi.AppHost project het bestand Program.cs.
Voeg de volgende gemarkeerde code toe aan de methode
ConfigureServices
: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();
Hiermee wordt het SupportTicketApi.MigrationService project als een service in de .NET.NET Aspire app-host opgenomen.
Belangrijk
Als u Visual Studiogebruikt en u de optie Enlist in Aspire orchestration hebt geselecteerd bij het maken van het Worker Service project, wordt soortgelijke code automatisch toegevoegd met de servicenaam
supportticketapi-migrationservice
. Vervang die code door de voorgaande code.
Bestaande seeding-code verwijderen
Aangezien de migratieservice de database zaait, moet u de bestaande gegevenszaaicode uit het API-project verwijderen.
Open in het SupportTicketApi.Api project het bestand Program.cs.
Verwijder de gemarkeerde regels.
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(); } } }
De migratieservice testen
Nu de migratieservice is geconfigureerd, voert u de app uit om de migraties te testen.
Voer de app uit en bekijk het SupportTicketApi dashboard.
Na een korte wachttijd wordt de status van de
migrations
-service weergegeven Voltooid.Selecteer de View koppeling in de migratieservice om de logboeken te onderzoeken met de SQL-opdrachten die zijn uitgevoerd.
De code ophalen
U vindt de voltooide voorbeeld-app op GitHub.
Meer voorbeeldcode
De Aspire Shop voorbeeld-app gebruikt deze benadering om migraties toe te passen. Zie het AspireShop.CatalogDbManager
project voor de implementatie van de migratieservice.