diff --git a/AsbCloudInfrastructure/Repository/ProcessMapPlanBaseRepository.cs b/AsbCloudInfrastructure/Repository/ProcessMapPlanBaseRepository.cs index 963dcaf1..9c6630b9 100644 --- a/AsbCloudInfrastructure/Repository/ProcessMapPlanBaseRepository.cs +++ b/AsbCloudInfrastructure/Repository/ProcessMapPlanBaseRepository.cs @@ -5,8 +5,10 @@ using AsbCloudApp.Requests; using AsbCloudApp.Services; using AsbCloudDb.Model; using AsbCloudDb.Model.ProcessMapPlan; +using AsbCloudDb.Model.WellSections; using Mapster; using Microsoft.EntityFrameworkCore; +using Npgsql; using System; using System.Collections.Generic; using System.Linq; @@ -47,8 +49,8 @@ public class ProcessMapPlanBaseRepository : IProcessMapPlanBaseRe entity.Obsolete = null; dbSet.Add(entity); } - - result += await context.SaveChangesAsync(token); + + result += await SaveChangesWithExceptionHandling(token); } return result; } @@ -60,28 +62,21 @@ public class ProcessMapPlanBaseRepository : IProcessMapPlanBaseRe using var transaction = context.Database.BeginTransaction(); var result = 0; - try + + var dbSet = context.Set(); + var entitiesToMarkDeleted = dbSet + .Where(e => e.IdWell == idWell) + .Where(e => e.Obsolete == null); + var obsolete = DateTimeOffset.UtcNow; + foreach (var entity in entitiesToMarkDeleted) { - var dbSet = context.Set(); - var entitiesToMarkDeleted = dbSet - .Where(e => e.IdWell == idWell) - .Where(e => e.Obsolete == null); - var obsolete = DateTimeOffset.UtcNow; - foreach (var entity in entitiesToMarkDeleted) - { - entity.IdState = ChangeLogAbstract.IdClearedOnImport; - entity.Obsolete = obsolete; - entity.IdEditor = idUser; - } - result += await context.SaveChangesAsync(token); - result += await InsertRange(idUser, dtos, token); - await transaction.CommitAsync(token); - } - catch - { - await transaction.RollbackAsync(CancellationToken.None); - throw; + entity.IdState = ChangeLogAbstract.IdClearedOnImport; + entity.Obsolete = obsolete; + entity.IdEditor = idUser; } + result += await SaveChangesWithExceptionHandling(token); + result += await InsertRange(idUser, dtos, token); + await transaction.CommitAsync(token); return result; } @@ -99,7 +94,7 @@ public class ProcessMapPlanBaseRepository : IProcessMapPlanBaseRe entity.Obsolete = obsolete; entity.IdEditor = idUser; } - var result = await context.SaveChangesAsync(token); + var result = await SaveChangesWithExceptionHandling(token); return result; } @@ -201,48 +196,39 @@ public class ProcessMapPlanBaseRepository : IProcessMapPlanBaseRe using var transaction = context.Database.BeginTransaction(); var result = 0; - try + + var ids = dtos.Select(d => d.Id); + var dbSet = context.Set(); + + var entitiesToDelete = dbSet + .Where(e => ids.Contains(e.Id)); + + var updateTime = DateTimeOffset.UtcNow; + foreach (var entity in entitiesToDelete) { - var ids = dtos.Select(d => d.Id); - var dbSet = context.Set(); - - var entitiesToDelete = dbSet - .Where(e => ids.Contains(e.Id)); - - var updateTime = DateTimeOffset.UtcNow; - foreach (var entity in entitiesToDelete) - { - if(entity.Obsolete is not null) - throw new ArgumentInvalidException(nameof(dtos), "Недопустимо редактировать устаревшие записи"); - entity.IdState = ChangeLogAbstract.IdStateReplaced; - entity.Obsolete = updateTime; - entity.IdEditor = idUser; - } - result += await context.SaveChangesAsync(token); - - var entitiesNew = dtos.Select(Convert); - foreach (var entity in entitiesNew) - { - entity.IdPrevious = entity.Id; - entity.Id = default; - entity.Creation = updateTime; - entity.IdAuthor = idUser; - entity.Obsolete = null; - entity.IdEditor = null; - entity.IdState = ChangeLogAbstract.IdStateActual; - dbSet.Add(entity); - } - - result += await context.SaveChangesAsync(token); - - await transaction.CommitAsync(token); + if(entity.Obsolete is not null) + throw new ArgumentInvalidException(nameof(dtos), "Недопустимо редактировать устаревшие записи"); + entity.IdState = ChangeLogAbstract.IdStateReplaced; + entity.Obsolete = updateTime; + entity.IdEditor = idUser; } - catch + result += await context.SaveChangesAsync(token); + + var entitiesNew = dtos.Select(Convert); + foreach (var entity in entitiesNew) { - await transaction.RollbackAsync(CancellationToken.None); - throw; + entity.IdPrevious = entity.Id; + entity.Id = default; + entity.Creation = updateTime; + entity.IdAuthor = idUser; + entity.Obsolete = null; + entity.IdEditor = null; + entity.IdState = ChangeLogAbstract.IdStateActual; + dbSet.Add(entity); } - + + result += await SaveChangesWithExceptionHandling(token); + await transaction.CommitAsync(token); return result; } @@ -267,4 +253,25 @@ public class ProcessMapPlanBaseRepository : IProcessMapPlanBaseRe return dto; } + + private async Task SaveChangesWithExceptionHandling(CancellationToken token) + { + try + { + var result = await context.SaveChangesAsync(token); + return result; + } + catch (DbUpdateException ex) + { + if (ex.InnerException is PostgresException pgException) + TryConvertPostgresExceptionToValidateException(pgException); + throw; + } + } + + private static void TryConvertPostgresExceptionToValidateException(PostgresException pgException) + { + if (pgException.SqlState == PostgresErrorCodes.ForeignKeyViolation) + throw new ArgumentInvalidException("dtos", pgException.Message + "\r\n" + pgException.Detail); + } } diff --git a/AsbCloudWebApi.IntegrationTests/Controllers/ProcessMapPlanDrillingControllerTest.cs b/AsbCloudWebApi.IntegrationTests/Controllers/ProcessMapPlanDrillingControllerTest.cs index 9a5f3844..4baa06d7 100644 --- a/AsbCloudWebApi.IntegrationTests/Controllers/ProcessMapPlanDrillingControllerTest.cs +++ b/AsbCloudWebApi.IntegrationTests/Controllers/ProcessMapPlanDrillingControllerTest.cs @@ -117,6 +117,57 @@ public class ProcessMapPlanDrillingControllerTest: BaseIntegrationTest MatchHelper.Match(expected, actual, excludeProps); } + [Fact] + public async Task InsertRange_returns_BadRequest_for_IdWellSectionType() + { + //arrange + var dbset = dbContext.Set(); + dbset.RemoveRange(dbset); + dbContext.SaveChanges(); + var badDto = dto.Adapt(); + badDto.IdWellSectionType = int.MaxValue; + + //act + var response = await client.InsertRange(dto.IdWell, new[] { badDto }); + + //assert + Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode); + } + + [Fact] + public async Task InsertRange_returns_BadRequest_for_IdMode() + { + //arrange + var dbset = dbContext.Set(); + dbset.RemoveRange(dbset); + dbContext.SaveChanges(); + var badDto = dto.Adapt(); + badDto.IdMode = int.MaxValue; + + //act + var response = await client.InsertRange(dto.IdWell, new[] { badDto }); + + //assert + Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode); + } + + [Fact] + public async Task InsertRange_returns_BadRequest_for_IdWell() + { + //arrange + var dbset = dbContext.Set(); + dbset.RemoveRange(dbset); + dbContext.SaveChanges(); + var badDto = dto.Adapt(); + badDto.IdWell = int.MaxValue; + + //act + var response = await client.InsertRange(dto.IdWell, new[] { badDto }); + + //assert + Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode); + } + [Fact] public async Task ClearAndInsertRange_returns_success() { diff --git a/AsbCloudWebApi/Rest/ProcessMapPlanDrillingController.http b/AsbCloudWebApi/Rest/ProcessMapPlanDrilling.http similarity index 87% rename from AsbCloudWebApi/Rest/ProcessMapPlanDrillingController.http rename to AsbCloudWebApi/Rest/ProcessMapPlanDrilling.http index 9d65d1b4..17ae5c40 100644 --- a/AsbCloudWebApi/Rest/ProcessMapPlanDrillingController.http +++ b/AsbCloudWebApi/Rest/ProcessMapPlanDrilling.http @@ -7,7 +7,7 @@ @id = 1 @idWell = 1 -### drill test +### получение данных drill test с панели и сохранение их в ЕЦП POST {{baseUrl}}/api/well/{{idWell}}/ProcessMapPlanDrilling Content-Type: {{contentType}} accept: */* @@ -54,12 +54,12 @@ Authorization: {{auth}} } ] -### +### Получение всех GET {{baseUrl}}/api/well/{{idWell}}/ProcessMapPlanDrilling accept: */* Authorization: {{auth}} -### +### замена старых записей новыми POST {{baseUrl}}/api/well/{{idWell}}/ProcessMapPlanDrilling/replace Content-Type: {{contentType}} accept: */* @@ -75,7 +75,7 @@ Authorization: {{auth}} "idState": 0, "idPrevious": 0, "idWell": 1, - "idWellSectionType": 1, + "idWellSectionType": 1500, "depthStart": 0, "depthEnd": 10, "idMode": 2, @@ -106,22 +106,22 @@ Authorization: {{auth}} } ] -### +### Получение только актуальных GET {{baseUrl}}/api/well/{{idWell}}/ProcessMapPlanDrilling?Moment=3000-01-01 accept: */* Authorization: {{auth}} -### +### Получение GET {{baseUrl}}/api/well/{{idWell}}/ProcessMapPlanDrilling/dates accept: */* Authorization: {{auth}} -### +### Получение изменений за дату GET {{baseUrl}}/api/well/{{idWell}}/ProcessMapPlanDrilling/changeLog?date=2024-01-19 accept: */* Authorization: {{auth}} -### +### удаление DELETE {{baseUrl}}/api/well/{{idWell}}/ProcessMapPlanDrilling Content-Type: {{contentType}} accept: */*