mirror of
https://github.com/Sea-Haven-Industries/shoc-backend.git
synced 2026-09-30 06:03:12 +00:00
fix(services): translate duplicate name races
This commit is contained in:
parent
45f98e8154
commit
dec8b15278
3 changed files with 61 additions and 4 deletions
|
|
@ -2,6 +2,7 @@ using Data.SeaHavenIndustries;
|
|||
using Data.SeaHavenIndustries.Enums;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using SeaHaven.DataServices.Interfaces;
|
||||
using SeaHaven.DataServices.Models;
|
||||
|
||||
namespace SeaHaven.DataServices.Implementation
|
||||
{
|
||||
|
|
@ -90,7 +91,15 @@ namespace SeaHaven.DataServices.Implementation
|
|||
public async Task<Service> AddServiceAsync(Service service, CancellationToken cancellationToken)
|
||||
{
|
||||
await _context.Services.AddAsync(service, cancellationToken);
|
||||
await _context.SaveChangesAsync(cancellationToken);
|
||||
try
|
||||
{
|
||||
await _context.SaveChangesAsync(cancellationToken);
|
||||
}
|
||||
catch (DbUpdateException ex) when (IsUniqueNameViolation(ex))
|
||||
{
|
||||
throw new ServicesRegistryDuplicateNameException(ex);
|
||||
}
|
||||
|
||||
return service;
|
||||
}
|
||||
|
||||
|
|
@ -112,7 +121,14 @@ namespace SeaHaven.DataServices.Implementation
|
|||
});
|
||||
}
|
||||
|
||||
await _context.SaveChangesAsync(cancellationToken);
|
||||
try
|
||||
{
|
||||
await _context.SaveChangesAsync(cancellationToken);
|
||||
}
|
||||
catch (DbUpdateException ex) when (IsUniqueNameViolation(ex))
|
||||
{
|
||||
throw new ServicesRegistryDuplicateNameException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<bool> DeactivateServiceAsync(int id, CancellationToken cancellationToken)
|
||||
|
|
@ -126,5 +142,14 @@ namespace SeaHaven.DataServices.Implementation
|
|||
await _context.SaveChangesAsync(cancellationToken);
|
||||
return true;
|
||||
}
|
||||
|
||||
private static bool IsUniqueNameViolation(DbUpdateException exception)
|
||||
{
|
||||
var message = exception.InnerException?.Message ?? exception.Message;
|
||||
return message.Contains("IX_Services_NormalizedName", StringComparison.OrdinalIgnoreCase)
|
||||
|| message.Contains("NormalizedName", StringComparison.OrdinalIgnoreCase)
|
||||
&& (message.Contains("duplicate", StringComparison.OrdinalIgnoreCase)
|
||||
|| message.Contains("unique", StringComparison.OrdinalIgnoreCase));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
14
SeaHaven.DataServices/Models/ServicesRegistryModels.cs
Normal file
14
SeaHaven.DataServices/Models/ServicesRegistryModels.cs
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
namespace SeaHaven.DataServices.Models
|
||||
{
|
||||
/// <summary>
|
||||
/// Raised by the registry data service when the database unique name index
|
||||
/// wins a concurrent create or update race.
|
||||
/// </summary>
|
||||
public sealed class ServicesRegistryDuplicateNameException : Exception
|
||||
{
|
||||
public ServicesRegistryDuplicateNameException(Exception innerException)
|
||||
: base("A service name is already in use.", innerException)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2,6 +2,7 @@ using System.Security.Claims;
|
|||
using Data.SeaHavenIndustries;
|
||||
using Data.SeaHavenIndustries.Enums;
|
||||
using SeaHaven.DataServices.Interfaces;
|
||||
using SeaHaven.DataServices.Models;
|
||||
using SeaHaven.Services.DTOs;
|
||||
using SeaHaven.Services.Exceptions;
|
||||
using SeaHaven.Services.Interfaces;
|
||||
|
|
@ -71,7 +72,14 @@ namespace SeaHaven.Services.Implementation
|
|||
.ToList()
|
||||
};
|
||||
|
||||
await _dataService.AddServiceAsync(service, cancellationToken);
|
||||
try
|
||||
{
|
||||
await _dataService.AddServiceAsync(service, cancellationToken);
|
||||
}
|
||||
catch (ServicesRegistryDuplicateNameException)
|
||||
{
|
||||
throw DuplicateName();
|
||||
}
|
||||
|
||||
var row = await _dataService.GetServiceRowByIdAsync(service.Id, cancellationToken);
|
||||
return MapToDto(row!);
|
||||
|
|
@ -101,7 +109,14 @@ namespace SeaHaven.Services.Implementation
|
|||
service.RequiresCompletionDocument = input.RequiresCompletionDocument;
|
||||
service.CompletionDocTemplateId = template?.Id;
|
||||
|
||||
await _dataService.SaveServiceAsync(service, supportedTypes, cancellationToken);
|
||||
try
|
||||
{
|
||||
await _dataService.SaveServiceAsync(service, supportedTypes, cancellationToken);
|
||||
}
|
||||
catch (ServicesRegistryDuplicateNameException)
|
||||
{
|
||||
throw DuplicateName();
|
||||
}
|
||||
|
||||
var row = await _dataService.GetServiceRowByIdAsync(id, cancellationToken);
|
||||
return MapToDto(row!);
|
||||
|
|
@ -123,6 +138,9 @@ namespace SeaHaven.Services.Implementation
|
|||
throw new ServicesRegistryValidationException("Forbidden", "Scheduler or Admin role is required.");
|
||||
}
|
||||
|
||||
private static ServicesRegistryValidationException DuplicateName() =>
|
||||
new("DuplicateName", "A service with this name already exists.");
|
||||
|
||||
private static string RequireValidName(string? name)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(name))
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue