From 1e9766b7ad81e315c5e41ea3a7ce3b144583f823 Mon Sep 17 00:00:00 2001 From: Ben Outram Date: Fri, 21 Jun 2024 14:42:13 +0100 Subject: [PATCH] fixup! EES-5235 Generate LocationOptionMeta and FilterOptionMetaLink PublicId Sqids based on Id sequences --- .../Fixture/TestApplicationFactory.cs | 2 +- .../FunctionsIntegrationTest.cs | 2 +- .../Fixture/TestApplicationFactory.cs | 2 +- .../Database/PublicDataDbContext.cs | 27 +++++++++++++-- ...FilterOptionMetaLinkIdSequence.Designer.cs | 2 +- ...S5235_AddFilterOptionMetaLinkIdSequence.cs | 4 +-- .../PublicDataDbContextModelSnapshot.cs | 2 +- .../Functions/ImportMetadataFunctionTests.cs | 16 ++++----- ...ocessorOptions.cs => AppSettingOptions.cs} | 6 ++-- .../ProcessorHostBuilder.cs | 6 ++-- .../Repository/FilterMetaRepository.cs | 20 ++++++----- .../Repository/LocationMetaRepository.cs | 20 ++++++----- .../appsettings.json | 6 ++-- .../Commands/SeedDataCommand.cs | 34 +++++++++++-------- 14 files changed, 90 insertions(+), 59 deletions(-) rename src/GovUk.Education.ExploreEducationStatistics.Public.Data.Processor/Options/{ProcessorOptions.cs => AppSettingOptions.cs} (66%) diff --git a/src/GovUk.Education.ExploreEducationStatistics.Admin.Tests/Fixture/TestApplicationFactory.cs b/src/GovUk.Education.ExploreEducationStatistics.Admin.Tests/Fixture/TestApplicationFactory.cs index 0ce55625a08..ec654d972e1 100644 --- a/src/GovUk.Education.ExploreEducationStatistics.Admin.Tests/Fixture/TestApplicationFactory.cs +++ b/src/GovUk.Education.ExploreEducationStatistics.Admin.Tests/Fixture/TestApplicationFactory.cs @@ -35,7 +35,7 @@ public async Task ClearTestData() where TDbContext : DbContext var tables = context.Model.GetEntityTypes() .Select(type => type.GetTableName()) .Distinct() - .Cast() + .OfType() .ToList(); foreach (var table in tables) diff --git a/src/GovUk.Education.ExploreEducationStatistics.Common.Tests/FunctionsIntegrationTest.cs b/src/GovUk.Education.ExploreEducationStatistics.Common.Tests/FunctionsIntegrationTest.cs index e3dc3a91766..dd85ab24fce 100644 --- a/src/GovUk.Education.ExploreEducationStatistics.Common.Tests/FunctionsIntegrationTest.cs +++ b/src/GovUk.Education.ExploreEducationStatistics.Common.Tests/FunctionsIntegrationTest.cs @@ -53,7 +53,7 @@ protected void ClearTestData() where TDbContext : DbContext var tables = context.Model.GetEntityTypes() .Select(type => type.GetTableName()) .Distinct() - .Cast() + .OfType() .ToList(); foreach (var table in tables) diff --git a/src/GovUk.Education.ExploreEducationStatistics.Public.Data.Api.Tests/Fixture/TestApplicationFactory.cs b/src/GovUk.Education.ExploreEducationStatistics.Public.Data.Api.Tests/Fixture/TestApplicationFactory.cs index d900714e54f..9a404b17141 100644 --- a/src/GovUk.Education.ExploreEducationStatistics.Public.Data.Api.Tests/Fixture/TestApplicationFactory.cs +++ b/src/GovUk.Education.ExploreEducationStatistics.Public.Data.Api.Tests/Fixture/TestApplicationFactory.cs @@ -32,7 +32,7 @@ public async Task ClearTestData() where TDbContext : DbContext var tables = context.Model.GetEntityTypes() .Select(type => type.GetTableName()) .Distinct() - .Cast() + .OfType() .ToList(); foreach (var table in tables) diff --git a/src/GovUk.Education.ExploreEducationStatistics.Public.Data.Model/Database/PublicDataDbContext.cs b/src/GovUk.Education.ExploreEducationStatistics.Public.Data.Model/Database/PublicDataDbContext.cs index 135623fd4a9..5b5f3d5d66e 100644 --- a/src/GovUk.Education.ExploreEducationStatistics.Public.Data.Model/Database/PublicDataDbContext.cs +++ b/src/GovUk.Education.ExploreEducationStatistics.Public.Data.Model/Database/PublicDataDbContext.cs @@ -1,3 +1,4 @@ +using System.Diagnostics.CodeAnalysis; using GovUk.Education.ExploreEducationStatistics.Common.Utils; using Microsoft.EntityFrameworkCore; @@ -5,7 +6,11 @@ namespace GovUk.Education.ExploreEducationStatistics.Public.Data.Model.Database; public class PublicDataDbContext : DbContext { - public PublicDataDbContext(DbContextOptions options, bool updateTimestamps = true) : base(options) + public const string FilterOptionMetaLinkSequence = "FilterOptionMetaLink_seq"; + public const string LocationOptionMetasIdSequence = "LocationOptionMetas_Id_seq"; + + public PublicDataDbContext( + DbContextOptions options, bool updateTimestamps = true) : base(options) { Configure(updateTimestamps: updateTimestamps); } @@ -23,7 +28,25 @@ protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.ApplyConfigurationsFromAssembly(typeof(PublicDataDbContext).Assembly); - modelBuilder.HasSequence("FilterOptionMetaLink_Id_seq"); + modelBuilder.HasSequence(FilterOptionMetaLinkSequence); + } + + [SuppressMessage("Security", "EF1002:Risk of vulnerability to SQL injection.")] + public Task NextSequenceValue(string sequenceName, CancellationToken cancellationToken = default) + { + return Database.SqlQueryRaw($""" + SELECT nextval('public."{sequenceName}"') AS "Value" + """) + .FirstAsync(cancellationToken); + } + + [SuppressMessage("Security", "EF1002:Risk of vulnerability to SQL injection.")] + public Task SetSequenceValue(string sequenceName, long value, CancellationToken cancellationToken = default) + { + return Database.SqlQueryRaw($""" + SELECT setval('public."{sequenceName}"', {value}) AS "Value" + """) + .FirstAsync(cancellationToken); } public DbSet DataSets { get; init; } = null!; diff --git a/src/GovUk.Education.ExploreEducationStatistics.Public.Data.Model/Migrations/20240619085713_EES5235_AddFilterOptionMetaLinkIdSequence.Designer.cs b/src/GovUk.Education.ExploreEducationStatistics.Public.Data.Model/Migrations/20240619085713_EES5235_AddFilterOptionMetaLinkIdSequence.Designer.cs index 98c71f9a02b..698f9afced6 100644 --- a/src/GovUk.Education.ExploreEducationStatistics.Public.Data.Model/Migrations/20240619085713_EES5235_AddFilterOptionMetaLinkIdSequence.Designer.cs +++ b/src/GovUk.Education.ExploreEducationStatistics.Public.Data.Model/Migrations/20240619085713_EES5235_AddFilterOptionMetaLinkIdSequence.Designer.cs @@ -26,7 +26,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); - modelBuilder.HasSequence("FilterOptionMetaLink_Id_seq"); + modelBuilder.HasSequence("FilterOptionMetaLink_seq"); modelBuilder.Entity("GovUk.Education.ExploreEducationStatistics.Public.Data.Model.ChangeSetFilterOptions", b => { diff --git a/src/GovUk.Education.ExploreEducationStatistics.Public.Data.Model/Migrations/20240619085713_EES5235_AddFilterOptionMetaLinkIdSequence.cs b/src/GovUk.Education.ExploreEducationStatistics.Public.Data.Model/Migrations/20240619085713_EES5235_AddFilterOptionMetaLinkIdSequence.cs index c6e1a8eed23..0c907ec6fbe 100644 --- a/src/GovUk.Education.ExploreEducationStatistics.Public.Data.Model/Migrations/20240619085713_EES5235_AddFilterOptionMetaLinkIdSequence.cs +++ b/src/GovUk.Education.ExploreEducationStatistics.Public.Data.Model/Migrations/20240619085713_EES5235_AddFilterOptionMetaLinkIdSequence.cs @@ -13,13 +13,13 @@ public partial class EES5235_AddFilterOptionMetaLinkIdSequence : Migration protected override void Up(MigrationBuilder migrationBuilder) { migrationBuilder.CreateSequence( - name: "FilterOptionMetaLink_Id_seq"); + name: "FilterOptionMetaLink_seq"); } /// protected override void Down(MigrationBuilder migrationBuilder) { migrationBuilder.DropSequence( - name: "FilterOptionMetaLink_Id_seq"); + name: "FilterOptionMetaLink_seq"); } } diff --git a/src/GovUk.Education.ExploreEducationStatistics.Public.Data.Model/Migrations/PublicDataDbContextModelSnapshot.cs b/src/GovUk.Education.ExploreEducationStatistics.Public.Data.Model/Migrations/PublicDataDbContextModelSnapshot.cs index dd7b9f3bb44..894a62d6ef7 100644 --- a/src/GovUk.Education.ExploreEducationStatistics.Public.Data.Model/Migrations/PublicDataDbContextModelSnapshot.cs +++ b/src/GovUk.Education.ExploreEducationStatistics.Public.Data.Model/Migrations/PublicDataDbContextModelSnapshot.cs @@ -23,7 +23,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); - modelBuilder.HasSequence("FilterOptionMetaLink_Id_seq"); + modelBuilder.HasSequence("FilterOptionMetaLink_seq"); modelBuilder.Entity("GovUk.Education.ExploreEducationStatistics.Public.Data.Model.ChangeSetFilterOptions", b => { diff --git a/src/GovUk.Education.ExploreEducationStatistics.Public.Data.Processor.Tests/Functions/ImportMetadataFunctionTests.cs b/src/GovUk.Education.ExploreEducationStatistics.Public.Data.Processor.Tests/Functions/ImportMetadataFunctionTests.cs index 14bfd962bb7..bc62a79e1a7 100644 --- a/src/GovUk.Education.ExploreEducationStatistics.Public.Data.Processor.Tests/Functions/ImportMetadataFunctionTests.cs +++ b/src/GovUk.Education.ExploreEducationStatistics.Public.Data.Processor.Tests/Functions/ImportMetadataFunctionTests.cs @@ -114,11 +114,11 @@ public async Task DataSetVersionMeta_CorrectGeographicLevels(ProcessorTestData t [Theory] [MemberData(nameof(TestDataFilesWithInsertBatchSize))] - public async Task DataSetVersionMeta_CorrectLocations(ProcessorTestData testData, int insertBatchSize) + public async Task DataSetVersionMeta_CorrectLocations(ProcessorTestData testData, int metaInsertBatchSize) { var (dataSetVersion, instanceId) = await CreateDataSet(Stage.PreviousStage()); - await ImportMetadata(testData, dataSetVersion, instanceId, insertBatchSize); + await ImportMetadata(testData, dataSetVersion, instanceId, metaInsertBatchSize); await using var publicDataDbContext = GetDbContext(); @@ -189,11 +189,11 @@ public async Task DataSetVersionMeta_CorrectTimePeriods(ProcessorTestData testDa [Theory] [MemberData(nameof(TestDataFilesWithInsertBatchSize))] - public async Task DataSetVersionMeta_CorrectFilters(ProcessorTestData testData, int insertBatchSize) + public async Task DataSetVersionMeta_CorrectFilters(ProcessorTestData testData, int metaInsertBatchSize) { var (dataSetVersion, instanceId) = await CreateDataSet(Stage.PreviousStage()); - await ImportMetadata(testData, dataSetVersion, instanceId, insertBatchSize); + await ImportMetadata(testData, dataSetVersion, instanceId, metaInsertBatchSize); await using var publicDataDbContext = GetDbContext(); @@ -422,15 +422,15 @@ private async Task ImportMetadata( ProcessorTestData testData, DataSetVersion dataSetVersion, Guid instanceId, - int? insertBatchSize = null) + int? metaInsertBatchSize = null) { SetupCsvDataFilesForDataSetVersion(testData, dataSetVersion); // Override default app configuration if provided - if (insertBatchSize.HasValue) + if (metaInsertBatchSize.HasValue) { - var processorOptions = GetRequiredService>(); - processorOptions.Value.InsertBatchSize = insertBatchSize.Value; + var appSettingOptions = GetRequiredService>(); + appSettingOptions.Value.MetaInsertBatchSize = metaInsertBatchSize.Value; } var function = GetRequiredService(); diff --git a/src/GovUk.Education.ExploreEducationStatistics.Public.Data.Processor/Options/ProcessorOptions.cs b/src/GovUk.Education.ExploreEducationStatistics.Public.Data.Processor/Options/AppSettingOptions.cs similarity index 66% rename from src/GovUk.Education.ExploreEducationStatistics.Public.Data.Processor/Options/ProcessorOptions.cs rename to src/GovUk.Education.ExploreEducationStatistics.Public.Data.Processor/Options/AppSettingOptions.cs index 63712b9788e..a02ef48bb94 100644 --- a/src/GovUk.Education.ExploreEducationStatistics.Public.Data.Processor/Options/ProcessorOptions.cs +++ b/src/GovUk.Education.ExploreEducationStatistics.Public.Data.Processor/Options/AppSettingOptions.cs @@ -1,12 +1,12 @@ namespace GovUk.Education.ExploreEducationStatistics.Public.Data.Processor.Options; -public class ProcessorOptions +public class AppSettingOptions { - public static readonly string Section = "Processor"; + public static readonly string Section = "AppSettings"; /// /// Batch size to use when inserting location option meta rows, location option meta link rows, /// and filter option meta link rows into the public data db. /// - public required int InsertBatchSize { get; set; } + public required int MetaInsertBatchSize { get; set; } } diff --git a/src/GovUk.Education.ExploreEducationStatistics.Public.Data.Processor/ProcessorHostBuilder.cs b/src/GovUk.Education.ExploreEducationStatistics.Public.Data.Processor/ProcessorHostBuilder.cs index e760fdb0ae4..f324a8ccf27 100644 --- a/src/GovUk.Education.ExploreEducationStatistics.Public.Data.Processor/ProcessorHostBuilder.cs +++ b/src/GovUk.Education.ExploreEducationStatistics.Public.Data.Processor/ProcessorHostBuilder.cs @@ -86,10 +86,10 @@ public static IHostBuilder ConfigureProcessorHostBuilder(this IHostBuilder hostB .AddScoped() .AddScoped, DataSetCreateRequest.Validator>() + .Configure( + hostBuilderContext.Configuration.GetSection(AppSettingOptions.Section)) .Configure( - hostBuilderContext.Configuration.GetSection(DataFilesOptions.Section)) - .Configure( - hostBuilderContext.Configuration.GetSection(ProcessorOptions.Section)); + hostBuilderContext.Configuration.GetSection(DataFilesOptions.Section)); }); } } diff --git a/src/GovUk.Education.ExploreEducationStatistics.Public.Data.Processor/Repository/FilterMetaRepository.cs b/src/GovUk.Education.ExploreEducationStatistics.Public.Data.Processor/Repository/FilterMetaRepository.cs index 49b35895833..ae3968d4252 100644 --- a/src/GovUk.Education.ExploreEducationStatistics.Public.Data.Processor/Repository/FilterMetaRepository.cs +++ b/src/GovUk.Education.ExploreEducationStatistics.Public.Data.Processor/Repository/FilterMetaRepository.cs @@ -16,9 +16,11 @@ namespace GovUk.Education.ExploreEducationStatistics.Public.Data.Processor.Repos public class FilterMetaRepository( PublicDataDbContext publicDataDbContext, - IOptions processorOptions, + IOptions appSettingOptions, IDataSetVersionPathResolver dataSetVersionPathResolver) : IFilterMetaRepository { + private readonly AppSettingOptions _appSettingOptions = appSettingOptions.Value; + public async Task CreateFilterMetas( IDuckDbConnection duckDbConnection, DataSetVersion dataSetVersion, @@ -82,10 +84,9 @@ await optionTable .InsertWhenNotMatched() .MergeAsync(cancellationToken); - var startIndex = (await publicDataDbContext.Database - .SqlQuery($"SELECT nextval('public.\"FilterOptionMetaLink_Id_seq\"')") - .ToListAsync(cancellationToken: cancellationToken)) - .First(); + var startIndex = await publicDataDbContext.NextSequenceValue( + PublicDataDbContext.FilterOptionMetaLinkSequence, + cancellationToken); var current = 0; @@ -94,7 +95,7 @@ await optionTable var batchStartIndex = startIndex + current; var batch = options .Skip(current) - .Take(processorOptions.Value.InsertBatchSize) + .Take(_appSettingOptions.MetaInsertBatchSize) .ToList(); // Although not necessary for filter options, we've adopted the 'row key' @@ -119,7 +120,7 @@ await optionTable publicDataDbContext.FilterOptionMetaLinks.AddRange(links); await publicDataDbContext.SaveChangesAsync(cancellationToken); - current += processorOptions.Value.InsertBatchSize; + current += _appSettingOptions.MetaInsertBatchSize; } var insertedLinks = await publicDataDbContext.FilterOptionMetaLinks @@ -133,8 +134,9 @@ await optionTable $"Inserted: {insertedLinks}, expected: {options.Count}"); } - await publicDataDbContext.Database.ExecuteSqlAsync( - $"SELECT setval('public.\"FilterOptionMetaLink_Id_seq\"', {startIndex + insertedLinks - 1})", + await publicDataDbContext.SetSequenceValue( + PublicDataDbContext.FilterOptionMetaLinkSequence, + startIndex + insertedLinks - 1, cancellationToken); } } diff --git a/src/GovUk.Education.ExploreEducationStatistics.Public.Data.Processor/Repository/LocationMetaRepository.cs b/src/GovUk.Education.ExploreEducationStatistics.Public.Data.Processor/Repository/LocationMetaRepository.cs index c4e3df5b748..ad7999d038f 100644 --- a/src/GovUk.Education.ExploreEducationStatistics.Public.Data.Processor/Repository/LocationMetaRepository.cs +++ b/src/GovUk.Education.ExploreEducationStatistics.Public.Data.Processor/Repository/LocationMetaRepository.cs @@ -22,9 +22,11 @@ namespace GovUk.Education.ExploreEducationStatistics.Public.Data.Processor.Repos public class LocationMetaRepository( PublicDataDbContext publicDataDbContext, - IOptions processorOptions, + IOptions appSettingOptions, IDataSetVersionPathResolver dataSetVersionPathResolver) : ILocationMetaRepository { + private readonly AppSettingOptions _appSettingOptions = appSettingOptions.Value; + public async Task CreateLocationMetas( IDuckDbConnection duckDbConnection, DataSetVersion dataSetVersion, @@ -78,7 +80,7 @@ FROM read_csv('{dataSetVersionPathResolver.CsvDataPath(dataSetVersion):raw}', AL { var batch = options .Skip(current) - .Take(processorOptions.Value.InsertBatchSize) + .Take(_appSettingOptions.MetaInsertBatchSize) .ToList(); // We create a 'row key' for each option that allows us to quickly @@ -114,10 +116,9 @@ FROM read_csv('{dataSetVersionPathResolver.CsvDataPath(dataSetVersion):raw}', AL .Where(o => !existingRowKeys.Contains(o.GetRowKey())) .ToList(); - var startIndex = (await publicDataDbContext.Database - .SqlQuery($"SELECT nextval('public.\"LocationOptionMetas_Id_seq\"')") - .ToListAsync(cancellationToken: cancellationToken)) - .First(); + var startIndex = await publicDataDbContext.NextSequenceValue( + PublicDataDbContext.LocationOptionMetasIdSequence, + cancellationToken); foreach (var option in newOptions) { @@ -129,8 +130,9 @@ await optionTable.BulkCopyAsync(new BulkCopyOptions { KeepIdentity = true }, newOptions, cancellationToken); - await publicDataDbContext.Database.ExecuteSqlAsync( - $"SELECT setval('public.\"LocationOptionMetas_Id_seq\"', {startIndex - 1})", + await publicDataDbContext.SetSequenceValue( + PublicDataDbContext.LocationOptionMetasIdSequence, + startIndex - 1, cancellationToken); } @@ -146,7 +148,7 @@ await publicDataDbContext.Database.ExecuteSqlAsync( publicDataDbContext.LocationOptionMetaLinks.AddRange(links); await publicDataDbContext.SaveChangesAsync(cancellationToken); - current += processorOptions.Value.InsertBatchSize; + current += _appSettingOptions.MetaInsertBatchSize; } var insertedLinks = await publicDataDbContext.LocationOptionMetaLinks diff --git a/src/GovUk.Education.ExploreEducationStatistics.Public.Data.Processor/appsettings.json b/src/GovUk.Education.ExploreEducationStatistics.Public.Data.Processor/appsettings.json index 6b93322f4d9..c5b9a323b73 100644 --- a/src/GovUk.Education.ExploreEducationStatistics.Public.Data.Processor/appsettings.json +++ b/src/GovUk.Education.ExploreEducationStatistics.Public.Data.Processor/appsettings.json @@ -6,10 +6,10 @@ } }, "CoreStorage": "DefaultEndpointsProtocol=http;AccountName=devstoreaccount1;AccountKey=Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==;BlobEndpoint=http://data-storage:10000/devstoreaccount1;QueueEndpoint=http://data-storage:10001/devstoreaccount1;TableEndpoint=http://data-storage:10002/devstoreaccount1", + "AppSettings": { + "MetaInsertBatchSize": 1000 + }, "DataFiles": { "BasePath": "data/public-api-data" - }, - "Processor": { - "InsertBatchSize": 1000 } } diff --git a/src/GovUk.Education.ExploreEducationStatistics.Public.Data.Scripts/Commands/SeedDataCommand.cs b/src/GovUk.Education.ExploreEducationStatistics.Public.Data.Scripts/Commands/SeedDataCommand.cs index 943fbedd05c..0ab60f9f2cf 100644 --- a/src/GovUk.Education.ExploreEducationStatistics.Public.Data.Scripts/Commands/SeedDataCommand.cs +++ b/src/GovUk.Education.ExploreEducationStatistics.Public.Data.Scripts/Commands/SeedDataCommand.cs @@ -111,7 +111,7 @@ private static async Task SetUpPublicDataDbContext(Cancella var tables = dbContext.Model.GetEntityTypes() .Select(type => type.GetTableName()) .Distinct() - .Cast() + .OfType() .ToList(); // Clear any tables in case we're re-running the command @@ -450,10 +450,10 @@ await optionTable .InsertWhenNotMatched() .MergeAsync(_cancellationToken); - var startIndex = (await _dbContext.Database - .SqlQuery($"SELECT nextval('public.\"FilterOptionMetaLink_Id_seq\"')") - .ToListAsync(cancellationToken: _cancellationToken)) - .First(); + var startIndex = await _dbContext.NextSequenceValue( + PublicDataDbContext.FilterOptionMetaLinkSequence, + _cancellationToken + ); var current = 0; const int batchSize = 1000; @@ -502,9 +502,11 @@ await optionTable $"Inserted: {insertedLinks}, expected: {options.Count}"); } - await _dbContext.Database.ExecuteSqlAsync( - $"SELECT setval('public.\"FilterOptionMetaLink_Id_seq\"', {startIndex + insertedLinks - 1})", - _cancellationToken); + await _dbContext.SetSequenceValue( + PublicDataDbContext.FilterOptionMetaLinkSequence, + startIndex + insertedLinks - 1, + _cancellationToken + ); } } @@ -594,10 +596,10 @@ FROM read_csv('{_dataFilePath:raw}', ALL_VARCHAR = true) .Where(o => !existingRowKeys.Contains(o.GetRowKey())) .ToList(); - var startIndex = (await _dbContext.Database - .SqlQuery($"SELECT nextval('public.\"LocationOptionMetas_Id_seq\"')") - .ToListAsync(cancellationToken: _cancellationToken)) - .First(); + var startIndex = await _dbContext.NextSequenceValue( + PublicDataDbContext.LocationOptionMetasIdSequence, + _cancellationToken + ); foreach (var option in newOptions) { @@ -609,9 +611,11 @@ await optionTable.BulkCopyAsync(new BulkCopyOptions { KeepIdentity = true }, newOptions, cancellationToken: _cancellationToken); - await _dbContext.Database.ExecuteSqlAsync( - $"SELECT setval('public.\"LocationOptionMetas_Id_seq\"', {startIndex - 1})", - _cancellationToken); + await _dbContext.SetSequenceValue( + PublicDataDbContext.LocationOptionMetasIdSequence, + startIndex - 1, + _cancellationToken + ); } var links = await optionTable