From f0b6a2dbd02655238c9e55d582825260d077e389 Mon Sep 17 00:00:00 2001 From: Bart Koelman <10324372+bkoelman@users.noreply.github.com> Date: Sat, 28 Jan 2023 18:35:05 +0100 Subject: [PATCH 1/2] Package updates; run tests against EF Core 7 --- .config/dotnet-tools.json | 4 ++-- Directory.Build.props | 12 ++++++------ benchmarks/Benchmarks.csproj | 2 +- src/Examples/JsonApiDotNetCoreExample/Program.cs | 6 +++--- src/Examples/NoEntityFrameworkExample/Program.cs | 6 +++--- test/SourceGeneratorTests/CompilationBuilder.cs | 8 +++++++- test/TestBuildingBlocks/FakeLoggerFactory.cs | 1 + test/TestBuildingBlocks/TestBuildingBlocks.csproj | 2 +- 8 files changed, 24 insertions(+), 17 deletions(-) diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json index f8589a73a7..da7dc3dede 100644 --- a/.config/dotnet-tools.json +++ b/.config/dotnet-tools.json @@ -9,7 +9,7 @@ ] }, "regitlint": { - "version": "6.2.1", + "version": "6.3.10", "commands": [ "regitlint" ] @@ -21,7 +21,7 @@ ] }, "dotnet-reportgenerator-globaltool": { - "version": "5.1.11", + "version": "5.1.15", "commands": [ "reportgenerator" ] diff --git a/Directory.Build.props b/Directory.Build.props index d641e8d6b6..15a7e94c7c 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -2,9 +2,9 @@ net6.0 6.0.* - 6.0.* - 6.0.* - 4.3.* + 7.0.* + 7.0.* + 4.4.* 2.14.1 5.1.2 $(MSBuildThisFileDirectory)CodingGuidelines.ruleset @@ -33,8 +33,8 @@ - 3.2.0 - 4.18.2 - 17.4.0 + 3.2.* + 4.18.* + 17.4.* diff --git a/benchmarks/Benchmarks.csproj b/benchmarks/Benchmarks.csproj index 3958713af4..185f2919ac 100644 --- a/benchmarks/Benchmarks.csproj +++ b/benchmarks/Benchmarks.csproj @@ -10,7 +10,7 @@ - + diff --git a/src/Examples/JsonApiDotNetCoreExample/Program.cs b/src/Examples/JsonApiDotNetCoreExample/Program.cs index bda826d131..e2fbc66ffd 100644 --- a/src/Examples/JsonApiDotNetCoreExample/Program.cs +++ b/src/Examples/JsonApiDotNetCoreExample/Program.cs @@ -47,7 +47,7 @@ static void ConfigureServices(WebApplicationBuilder builder) builder.Services.AddDbContext(options => { - string connectionString = GetConnectionString(builder.Configuration); + string? connectionString = GetConnectionString(builder.Configuration); options.UseNpgsql(connectionString); #if DEBUG @@ -73,10 +73,10 @@ static void ConfigureServices(WebApplicationBuilder builder) } } -static string GetConnectionString(IConfiguration configuration) +static string? GetConnectionString(IConfiguration configuration) { string postgresPassword = Environment.GetEnvironmentVariable("PGPASSWORD") ?? "postgres"; - return configuration["Data:DefaultConnection"].Replace("###", postgresPassword); + return configuration["Data:DefaultConnection"]?.Replace("###", postgresPassword); } static void ConfigurePipeline(WebApplication webApplication) diff --git a/src/Examples/NoEntityFrameworkExample/Program.cs b/src/Examples/NoEntityFrameworkExample/Program.cs index 43a14f7896..363b58b19e 100755 --- a/src/Examples/NoEntityFrameworkExample/Program.cs +++ b/src/Examples/NoEntityFrameworkExample/Program.cs @@ -7,7 +7,7 @@ // Add services to the container. -string connectionString = GetConnectionString(builder.Configuration); +string? connectionString = GetConnectionString(builder.Configuration); builder.Services.AddNpgsql(connectionString); builder.Services.AddJsonApi(options => options.Namespace = "api/v1", resources: resourceGraphBuilder => resourceGraphBuilder.Add()); @@ -26,10 +26,10 @@ app.Run(); -static string GetConnectionString(IConfiguration configuration) +static string? GetConnectionString(IConfiguration configuration) { string postgresPassword = Environment.GetEnvironmentVariable("PGPASSWORD") ?? "postgres"; - return configuration["Data:DefaultConnection"].Replace("###", postgresPassword); + return configuration["Data:DefaultConnection"]?.Replace("###", postgresPassword); } static async Task CreateDatabaseAsync(IServiceProvider serviceProvider) diff --git a/test/SourceGeneratorTests/CompilationBuilder.cs b/test/SourceGeneratorTests/CompilationBuilder.cs index 6029b68eae..b4830e25f3 100644 --- a/test/SourceGeneratorTests/CompilationBuilder.cs +++ b/test/SourceGeneratorTests/CompilationBuilder.cs @@ -9,7 +9,13 @@ namespace SourceGeneratorTests; internal sealed class CompilationBuilder { - private static readonly CSharpCompilationOptions DefaultOptions = new(OutputKind.DynamicallyLinkedLibrary); + private static readonly CSharpCompilationOptions DefaultOptions = + new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary).WithSpecificDiagnosticOptions(new Dictionary + { + // Suppress warning for version conflict on Microsoft.Extensions.Logging.Abstractions: + // JsonApiDotNetCore indirectly depends on v6 (via Entity Framework Core 6), whereas Entity Framework Core 7 depends on v7. + ["CS1701"] = ReportDiagnostic.Suppress + }); private readonly HashSet _syntaxTrees = new(); private readonly HashSet _references = new(); diff --git a/test/TestBuildingBlocks/FakeLoggerFactory.cs b/test/TestBuildingBlocks/FakeLoggerFactory.cs index e490cdda7b..1a1ac6d402 100644 --- a/test/TestBuildingBlocks/FakeLoggerFactory.cs +++ b/test/TestBuildingBlocks/FakeLoggerFactory.cs @@ -59,6 +59,7 @@ public void Log(LogLevel logLevel, EventId eventId, TState state, Except } public IDisposable BeginScope(TState state) + where TState : notnull { return NullScope.Instance; } diff --git a/test/TestBuildingBlocks/TestBuildingBlocks.csproj b/test/TestBuildingBlocks/TestBuildingBlocks.csproj index ce8c54ef3b..999498ebaa 100644 --- a/test/TestBuildingBlocks/TestBuildingBlocks.csproj +++ b/test/TestBuildingBlocks/TestBuildingBlocks.csproj @@ -10,7 +10,7 @@ - + From ab8759cc8444d05157302dda68c63753c3e9a1a8 Mon Sep 17 00:00:00 2001 From: Bart Koelman <10324372+bkoelman@users.noreply.github.com> Date: Tue, 31 Jan 2023 09:58:13 +0100 Subject: [PATCH 2/2] Added tests for EF Core table-per-concrete-type inheritance mode https://learn.microsoft.com/en-us/ef/core/modeling/inheritance#table-per-concrete-type-configuration --- .../ResourceInheritanceWriteTests.cs | 16 ++++++--- .../TablePerConcreteTypeDbContext.cs | 33 +++++++++++++++++++ .../TablePerConcreteTypeReadTests.cs | 13 ++++++++ .../TablePerConcreteTypeWriteTests.cs | 13 ++++++++ .../TablePerType/TablePerTypeDbContext.cs | 31 ++++++++--------- .../TestBuildingBlocks/DbContextExtensions.cs | 14 ++++++-- 6 files changed, 96 insertions(+), 24 deletions(-) create mode 100644 test/JsonApiDotNetCoreTests/IntegrationTests/ResourceInheritance/TablePerConcreteType/TablePerConcreteTypeDbContext.cs create mode 100644 test/JsonApiDotNetCoreTests/IntegrationTests/ResourceInheritance/TablePerConcreteType/TablePerConcreteTypeReadTests.cs create mode 100644 test/JsonApiDotNetCoreTests/IntegrationTests/ResourceInheritance/TablePerConcreteType/TablePerConcreteTypeWriteTests.cs diff --git a/test/JsonApiDotNetCoreTests/IntegrationTests/ResourceInheritance/ResourceInheritanceWriteTests.cs b/test/JsonApiDotNetCoreTests/IntegrationTests/ResourceInheritance/ResourceInheritanceWriteTests.cs index 0dd9659593..c3d7f1fb9c 100644 --- a/test/JsonApiDotNetCoreTests/IntegrationTests/ResourceInheritance/ResourceInheritanceWriteTests.cs +++ b/test/JsonApiDotNetCoreTests/IntegrationTests/ResourceInheritance/ResourceInheritanceWriteTests.cs @@ -2298,7 +2298,7 @@ public async Task Can_add_concrete_base_resources_stored_as_derived_at_ToMany_re await _testContext.RunOnDatabaseAsync(async dbContext => { - dbContext.Set().Add(existingManufacturer); + dbContext.VehicleManufacturers.Add(existingManufacturer); dbContext.Vehicles.Add(existingTandem); await dbContext.SaveChangesAsync(); }); @@ -2327,9 +2327,17 @@ await _testContext.RunOnDatabaseAsync(async dbContext => await _testContext.RunOnDatabaseAsync(async dbContext => { - VehicleManufacturer manufacturerInDatabase = await dbContext.Set().Include(manufacturer => manufacturer.Vehicles) + // @formatter:wrap_chained_method_calls chop_always + // @formatter:keep_existing_linebreaks true + + VehicleManufacturer manufacturerInDatabase = await dbContext.VehicleManufacturers + .Include(manufacturer => manufacturer.Vehicles + .OrderByDescending(vehicle => vehicle.Id)) .FirstWithIdAsync(existingManufacturer.Id); + // @formatter:keep_existing_linebreaks restore + // @formatter:wrap_chained_method_calls restore + manufacturerInDatabase.Vehicles.ShouldHaveCount(2); manufacturerInDatabase.Vehicles.ElementAt(0).Should().BeOfType(); manufacturerInDatabase.Vehicles.ElementAt(0).Id.Should().Be(existingManufacturer.Vehicles.ElementAt(0).Id); @@ -2578,7 +2586,7 @@ public async Task Can_remove_concrete_base_resources_stored_as_derived_at_ToMany await _testContext.RunOnDatabaseAsync(async dbContext => { - dbContext.Set().Add(existingManufacturer); + dbContext.VehicleManufacturers.Add(existingManufacturer); await dbContext.SaveChangesAsync(); }); @@ -2606,7 +2614,7 @@ await _testContext.RunOnDatabaseAsync(async dbContext => await _testContext.RunOnDatabaseAsync(async dbContext => { - VehicleManufacturer manufacturerInDatabase = await dbContext.Set().Include(manufacturer => manufacturer.Vehicles) + VehicleManufacturer manufacturerInDatabase = await dbContext.VehicleManufacturers.Include(manufacturer => manufacturer.Vehicles) .FirstWithIdAsync(existingManufacturer.Id); manufacturerInDatabase.Vehicles.ShouldHaveCount(1); diff --git a/test/JsonApiDotNetCoreTests/IntegrationTests/ResourceInheritance/TablePerConcreteType/TablePerConcreteTypeDbContext.cs b/test/JsonApiDotNetCoreTests/IntegrationTests/ResourceInheritance/TablePerConcreteType/TablePerConcreteTypeDbContext.cs new file mode 100644 index 0000000000..2b5977c8b4 --- /dev/null +++ b/test/JsonApiDotNetCoreTests/IntegrationTests/ResourceInheritance/TablePerConcreteType/TablePerConcreteTypeDbContext.cs @@ -0,0 +1,33 @@ +using JetBrains.Annotations; +using JsonApiDotNetCoreTests.IntegrationTests.ResourceInheritance.Models; +using Microsoft.EntityFrameworkCore; + +// @formatter:wrap_chained_method_calls chop_always + +namespace JsonApiDotNetCoreTests.IntegrationTests.ResourceInheritance.TablePerConcreteType; + +[UsedImplicitly(ImplicitUseTargetFlags.Members)] +public sealed class TablePerConcreteTypeDbContext : ResourceInheritanceDbContext +{ + public TablePerConcreteTypeDbContext(DbContextOptions options) + : base(options) + { + } + + protected override void OnModelCreating(ModelBuilder builder) + { + builder.Entity() + .UseTpcMappingStrategy(); + + builder.Entity() + .UseTpcMappingStrategy(); + + builder.Entity() + .UseTpcMappingStrategy(); + + builder.Entity() + .UseTpcMappingStrategy(); + + base.OnModelCreating(builder); + } +} diff --git a/test/JsonApiDotNetCoreTests/IntegrationTests/ResourceInheritance/TablePerConcreteType/TablePerConcreteTypeReadTests.cs b/test/JsonApiDotNetCoreTests/IntegrationTests/ResourceInheritance/TablePerConcreteType/TablePerConcreteTypeReadTests.cs new file mode 100644 index 0000000000..bcffe2ed5e --- /dev/null +++ b/test/JsonApiDotNetCoreTests/IntegrationTests/ResourceInheritance/TablePerConcreteType/TablePerConcreteTypeReadTests.cs @@ -0,0 +1,13 @@ +using JetBrains.Annotations; +using TestBuildingBlocks; + +namespace JsonApiDotNetCoreTests.IntegrationTests.ResourceInheritance.TablePerConcreteType; + +[UsedImplicitly(ImplicitUseKindFlags.InstantiatedNoFixedConstructorSignature)] +public sealed class TablePerConcreteTypeReadTests : ResourceInheritanceReadTests +{ + public TablePerConcreteTypeReadTests(IntegrationTestContext, TablePerConcreteTypeDbContext> testContext) + : base(testContext) + { + } +} diff --git a/test/JsonApiDotNetCoreTests/IntegrationTests/ResourceInheritance/TablePerConcreteType/TablePerConcreteTypeWriteTests.cs b/test/JsonApiDotNetCoreTests/IntegrationTests/ResourceInheritance/TablePerConcreteType/TablePerConcreteTypeWriteTests.cs new file mode 100644 index 0000000000..9f2e3c3cae --- /dev/null +++ b/test/JsonApiDotNetCoreTests/IntegrationTests/ResourceInheritance/TablePerConcreteType/TablePerConcreteTypeWriteTests.cs @@ -0,0 +1,13 @@ +using JetBrains.Annotations; +using TestBuildingBlocks; + +namespace JsonApiDotNetCoreTests.IntegrationTests.ResourceInheritance.TablePerConcreteType; + +[UsedImplicitly(ImplicitUseKindFlags.InstantiatedNoFixedConstructorSignature)] +public sealed class TablePerConcreteTypeWriteTests : ResourceInheritanceWriteTests +{ + public TablePerConcreteTypeWriteTests(IntegrationTestContext, TablePerConcreteTypeDbContext> testContext) + : base(testContext) + { + } +} diff --git a/test/JsonApiDotNetCoreTests/IntegrationTests/ResourceInheritance/TablePerType/TablePerTypeDbContext.cs b/test/JsonApiDotNetCoreTests/IntegrationTests/ResourceInheritance/TablePerType/TablePerTypeDbContext.cs index 7c50ee5573..86a723bfd3 100644 --- a/test/JsonApiDotNetCoreTests/IntegrationTests/ResourceInheritance/TablePerType/TablePerTypeDbContext.cs +++ b/test/JsonApiDotNetCoreTests/IntegrationTests/ResourceInheritance/TablePerType/TablePerTypeDbContext.cs @@ -2,6 +2,8 @@ using JsonApiDotNetCoreTests.IntegrationTests.ResourceInheritance.Models; using Microsoft.EntityFrameworkCore; +// @formatter:wrap_chained_method_calls chop_always + namespace JsonApiDotNetCoreTests.IntegrationTests.ResourceInheritance.TablePerType; [UsedImplicitly(ImplicitUseTargetFlags.Members)] @@ -14,24 +16,17 @@ public TablePerTypeDbContext(DbContextOptions options) protected override void OnModelCreating(ModelBuilder builder) { - builder.Entity().ToTable("Vehicles"); - builder.Entity().ToTable("Bikes"); - builder.Entity().ToTable("Tandems"); - builder.Entity().ToTable("MotorVehicles"); - builder.Entity().ToTable("Cars"); - builder.Entity().ToTable("Trucks"); - - builder.Entity().ToTable("Wheels"); - builder.Entity().ToTable("CarbonWheels"); - builder.Entity().ToTable("ChromeWheels"); - - builder.Entity().ToTable("Engines"); - builder.Entity().ToTable("GasolineEngines"); - builder.Entity().ToTable("DieselEngines"); - - builder.Entity().ToTable("GenericProperties"); - builder.Entity().ToTable("StringProperties"); - builder.Entity().ToTable("NumberProperties"); + builder.Entity() + .UseTptMappingStrategy(); + + builder.Entity() + .UseTptMappingStrategy(); + + builder.Entity() + .UseTptMappingStrategy(); + + builder.Entity() + .UseTptMappingStrategy(); base.OnModelCreating(builder); } diff --git a/test/TestBuildingBlocks/DbContextExtensions.cs b/test/TestBuildingBlocks/DbContextExtensions.cs index 5bb3f81a14..8ce859f356 100644 --- a/test/TestBuildingBlocks/DbContextExtensions.cs +++ b/test/TestBuildingBlocks/DbContextExtensions.cs @@ -34,8 +34,18 @@ private static async Task ClearTablesAsync(this DbContext dbContext, params Type throw new InvalidOperationException($"Table for '{model.Name}' not found."); } - string tableName = entityType.GetTableName()!; - await dbContext.Database.ExecuteSqlRawAsync($"delete from \"{tableName}\""); + string? tableName = entityType.GetTableName(); + + if (tableName == null) + { + // There is no table for the specified abstract base type when using TablePerConcreteType inheritance. + IEnumerable derivedTypes = entityType.GetConcreteDerivedTypesInclusive(); + await ClearTablesAsync(dbContext, derivedTypes.Select(derivedType => derivedType.ClrType).ToArray()); + } + else + { + await dbContext.Database.ExecuteSqlRawAsync($"delete from \"{tableName}\""); + } } } }