From e93ff0ad8cf0baa3db89b857de71b793739790e6 Mon Sep 17 00:00:00 2001 From: Vladimir Pecanac Date: Tue, 15 Sep 2026 15:18:42 +0200 Subject: [PATCH] Unique constraints in EF Core: retarget net10.0, EF Core 10, built-in OpenAPI Retarget both projects from net8.0 to net10.0. Packages: EF Core and EF Core SqlServer 8.0.2 to 10.0.12, AspNetCore.OpenApi 8.0.2 to 10.0.12, Mvc.Testing 8.0.2 to 10.0.12, Test.Sdk 17.8.0 to 18.10.1, xunit 2.5.3 to 2.9.3, xunit.runner.visualstudio 2.5.3 to 4.0.0, coverlet 6.0.0 to 10.0.1, Testcontainers.MsSql 3.7.0 to 4.15.0, FluentAssertions 6.12.0 to 7.2.2. Removed Swashbuckle.AspNetCore (replaced by AddOpenApi and MapOpenApi) and EntityFrameworkCore.InMemory (referenced by no source file). Code: - Planet gains OrbitalPeriod, which the article's composite index examples use. - Program.cs: AddOpenApi/MapOpenApi in place of Swagger; Add instead of AddAsync (the async form exists for value generators that hit the database); catch (DbUpdateException) instead of a bare catch, which is the exception a unique index violation arrives as; .WithOpenApi() dropped, deprecated on .NET 10 (ASPDEPR002). - SolarSystemApiApplicationFactory: MsSqlBuilder takes the image parameter, the parameterless constructor is obsolete on Testcontainers 4.x (CS0618). - Connection string: Database=SolarSystem instead of Database=Master, so the sample stops creating its tables in the server's master database. - Both live tests set OrbitalPeriod, now a required member. Build: 0 errors, 0 warnings on SDK 10.0.302. Repo CI runs no tests in this folder, its filter excludes every Live-named test. --- .../AddPlanetEndpointLiveTests.cs | 8 +++++--- .../SolarSystemApiApplicationFactory.cs | 4 ++-- .../UniqueConstraintsInEFCore.Tests.csproj | 16 ++++++++-------- .../Data/Models/Planet.cs | 1 + .../UniqueConstraintsInEFCore/Program.cs | 15 ++++++--------- .../UniqueConstraintsInEFCore.csproj | 10 ++++------ .../UniqueConstraintsInEFCore/appsettings.json | 4 ++-- 7 files changed, 28 insertions(+), 30 deletions(-) diff --git a/dotnet-efcore/UniqueConstraintsInEFCore/UniqueConstraintsInEFCore.Tests/AddPlanetEndpointLiveTests.cs b/dotnet-efcore/UniqueConstraintsInEFCore/UniqueConstraintsInEFCore.Tests/AddPlanetEndpointLiveTests.cs index b959075e30..4f762cb405 100644 --- a/dotnet-efcore/UniqueConstraintsInEFCore/UniqueConstraintsInEFCore.Tests/AddPlanetEndpointLiveTests.cs +++ b/dotnet-efcore/UniqueConstraintsInEFCore/UniqueConstraintsInEFCore.Tests/AddPlanetEndpointLiveTests.cs @@ -12,7 +12,8 @@ public async Task GivenThatPlanetDoesNotExist_WhenAddPlanetEndpointIsInvoked_The { Name = "Mars", Mass = 6.4171, - Radius = 3389.5 + Radius = 3389.5, + OrbitalPeriod = 686.98 }; // Act @@ -30,8 +31,9 @@ public async Task GivenThatPlanetExist_WhenAddPlanetEndpointIsInvoked_Then400IsR var planet = new Planet { Name = "Venus", - Mass = 6.4171, - Radius = 3389.5 + Mass = 4.8675, + Radius = 6051.8, + OrbitalPeriod = 224.7 }; // Act diff --git a/dotnet-efcore/UniqueConstraintsInEFCore/UniqueConstraintsInEFCore.Tests/SolarSystemApiApplicationFactory.cs b/dotnet-efcore/UniqueConstraintsInEFCore/UniqueConstraintsInEFCore.Tests/SolarSystemApiApplicationFactory.cs index f208a63a9a..23a05fa7e3 100644 --- a/dotnet-efcore/UniqueConstraintsInEFCore/UniqueConstraintsInEFCore.Tests/SolarSystemApiApplicationFactory.cs +++ b/dotnet-efcore/UniqueConstraintsInEFCore/UniqueConstraintsInEFCore.Tests/SolarSystemApiApplicationFactory.cs @@ -1,8 +1,8 @@ -namespace UniqueConstraintsInEFCore.Tests; +namespace UniqueConstraintsInEFCore.Tests; public class SolarSystemApiApplicationFactory : WebApplicationFactory, IAsyncLifetime { - private readonly MsSqlContainer _msSqlContainer = new MsSqlBuilder().Build(); + private readonly MsSqlContainer _msSqlContainer = new MsSqlBuilder("mcr.microsoft.com/mssql/server:2022-latest").Build(); protected override void ConfigureWebHost(IWebHostBuilder builder) { diff --git a/dotnet-efcore/UniqueConstraintsInEFCore/UniqueConstraintsInEFCore.Tests/UniqueConstraintsInEFCore.Tests.csproj b/dotnet-efcore/UniqueConstraintsInEFCore/UniqueConstraintsInEFCore.Tests/UniqueConstraintsInEFCore.Tests.csproj index febc8f6e53..0d79f840cb 100644 --- a/dotnet-efcore/UniqueConstraintsInEFCore/UniqueConstraintsInEFCore.Tests/UniqueConstraintsInEFCore.Tests.csproj +++ b/dotnet-efcore/UniqueConstraintsInEFCore/UniqueConstraintsInEFCore.Tests/UniqueConstraintsInEFCore.Tests.csproj @@ -1,7 +1,7 @@ - net8.0 + net10.0 enable enable @@ -10,13 +10,13 @@ - - - - - - - + + + + + + + diff --git a/dotnet-efcore/UniqueConstraintsInEFCore/UniqueConstraintsInEFCore/Data/Models/Planet.cs b/dotnet-efcore/UniqueConstraintsInEFCore/UniqueConstraintsInEFCore/Data/Models/Planet.cs index a60d6f14da..ce7cf8a46b 100644 --- a/dotnet-efcore/UniqueConstraintsInEFCore/UniqueConstraintsInEFCore/Data/Models/Planet.cs +++ b/dotnet-efcore/UniqueConstraintsInEFCore/UniqueConstraintsInEFCore/Data/Models/Planet.cs @@ -9,4 +9,5 @@ public class Planet public required string Name { get; set; } public required double Mass { get; set; } public required double Radius { get; set; } + public required double OrbitalPeriod { get; set; } } diff --git a/dotnet-efcore/UniqueConstraintsInEFCore/UniqueConstraintsInEFCore/Program.cs b/dotnet-efcore/UniqueConstraintsInEFCore/UniqueConstraintsInEFCore/Program.cs index 4fd031d1aa..695b707fc4 100644 --- a/dotnet-efcore/UniqueConstraintsInEFCore/UniqueConstraintsInEFCore/Program.cs +++ b/dotnet-efcore/UniqueConstraintsInEFCore/UniqueConstraintsInEFCore/Program.cs @@ -1,12 +1,11 @@ -using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore; using UniqueConstraintsInEFCore.Data; using UniqueConstraintsInEFCore.Data.Models; using UniqueConstraintsInEFCore.Services; var builder = WebApplication.CreateBuilder(args); -builder.Services.AddEndpointsApiExplorer(); -builder.Services.AddSwaggerGen(); +builder.Services.AddOpenApi(); builder.Services.AddHostedService(); @@ -17,8 +16,7 @@ if (app.Environment.IsDevelopment()) { - app.UseSwagger(); - app.UseSwaggerUI(); + app.MapOpenApi(); } app.UseHttpsRedirection(); @@ -27,18 +25,17 @@ { try { - await context.Planets.AddAsync(planet); + context.Planets.Add(planet); await context.SaveChangesAsync(); return Results.Created($"/planets/{planet.Id}", planet); } - catch + catch (DbUpdateException) { return Results.BadRequest(); } }) -.WithName("AddPlanet") -.WithOpenApi(); +.WithName("AddPlanet"); app.Run(); diff --git a/dotnet-efcore/UniqueConstraintsInEFCore/UniqueConstraintsInEFCore/UniqueConstraintsInEFCore.csproj b/dotnet-efcore/UniqueConstraintsInEFCore/UniqueConstraintsInEFCore/UniqueConstraintsInEFCore.csproj index 1d2e88708a..2a3da1355a 100644 --- a/dotnet-efcore/UniqueConstraintsInEFCore/UniqueConstraintsInEFCore/UniqueConstraintsInEFCore.csproj +++ b/dotnet-efcore/UniqueConstraintsInEFCore/UniqueConstraintsInEFCore/UniqueConstraintsInEFCore.csproj @@ -1,17 +1,15 @@ - net8.0 + net10.0 enable enable - - - - - + + + diff --git a/dotnet-efcore/UniqueConstraintsInEFCore/UniqueConstraintsInEFCore/appsettings.json b/dotnet-efcore/UniqueConstraintsInEFCore/UniqueConstraintsInEFCore/appsettings.json index b2d5f27130..80d1280866 100644 --- a/dotnet-efcore/UniqueConstraintsInEFCore/UniqueConstraintsInEFCore/appsettings.json +++ b/dotnet-efcore/UniqueConstraintsInEFCore/UniqueConstraintsInEFCore/appsettings.json @@ -1,4 +1,4 @@ -{ +{ "Logging": { "LogLevel": { "Default": "Information", @@ -7,6 +7,6 @@ }, "AllowedHosts": "*", "ConnectionStrings": { - "SolarSystemDatabase": "Server=127.0.0.1,1433; Database=Master ;User Id=SA; Password=yourStrong(!)Password; TrustServerCertificate=True" + "SolarSystemDatabase": "Server=127.0.0.1,1433; Database=SolarSystem;User Id=SA; Password=yourStrong(!)Password; TrustServerCertificate=True" } }