fix(uns): guard scripted-alarm name uniqueness on create/update (code-review)
This commit is contained in:
@@ -1316,6 +1316,9 @@ public sealed class UnsTreeService(IDbContextFactory<OtOpcUaConfigDbContext> dbF
|
|||||||
if (await db.ScriptedAlarms.AnyAsync(a => a.ScriptedAlarmId == input.ScriptedAlarmId, ct))
|
if (await db.ScriptedAlarms.AnyAsync(a => a.ScriptedAlarmId == input.ScriptedAlarmId, ct))
|
||||||
return new UnsMutationResult(false, $"ScriptedAlarm '{input.ScriptedAlarmId}' already exists.");
|
return new UnsMutationResult(false, $"ScriptedAlarm '{input.ScriptedAlarmId}' already exists.");
|
||||||
|
|
||||||
|
if (await db.ScriptedAlarms.AnyAsync(a => a.EquipmentId == equipmentId && a.Name == input.Name, ct))
|
||||||
|
return new UnsMutationResult(false, $"A scripted alarm named '{input.Name}' already exists on this equipment.");
|
||||||
|
|
||||||
db.ScriptedAlarms.Add(new ScriptedAlarm
|
db.ScriptedAlarms.Add(new ScriptedAlarm
|
||||||
{
|
{
|
||||||
ScriptedAlarmId = input.ScriptedAlarmId,
|
ScriptedAlarmId = input.ScriptedAlarmId,
|
||||||
@@ -1338,7 +1341,14 @@ public sealed class UnsTreeService(IDbContextFactory<OtOpcUaConfigDbContext> dbF
|
|||||||
{
|
{
|
||||||
await using var db = await dbFactory.CreateDbContextAsync(ct);
|
await using var db = await dbFactory.CreateDbContextAsync(ct);
|
||||||
var entity = await db.ScriptedAlarms.FirstOrDefaultAsync(a => a.ScriptedAlarmId == scriptedAlarmId, ct);
|
var entity = await db.ScriptedAlarms.FirstOrDefaultAsync(a => a.ScriptedAlarmId == scriptedAlarmId, ct);
|
||||||
if (entity is null) return new UnsMutationResult(false, "Row no longer exists.");
|
if (entity is null)
|
||||||
|
{
|
||||||
|
return new UnsMutationResult(false, "Row no longer exists.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (await db.ScriptedAlarms.AnyAsync(a => a.EquipmentId == entity.EquipmentId && a.Name == input.Name && a.ScriptedAlarmId != scriptedAlarmId, ct))
|
||||||
|
return new UnsMutationResult(false, $"A scripted alarm named '{input.Name}' already exists on this equipment.");
|
||||||
|
|
||||||
db.Entry(entity).Property(e => e.RowVersion).OriginalValue = rowVersion;
|
db.Entry(entity).Property(e => e.RowVersion).OriginalValue = rowVersion;
|
||||||
entity.Name = input.Name;
|
entity.Name = input.Name;
|
||||||
entity.AlarmType = input.AlarmType;
|
entity.AlarmType = input.AlarmType;
|
||||||
@@ -1348,8 +1358,16 @@ public sealed class UnsTreeService(IDbContextFactory<OtOpcUaConfigDbContext> dbF
|
|||||||
entity.HistorizeToAveva = input.HistorizeToAveva;
|
entity.HistorizeToAveva = input.HistorizeToAveva;
|
||||||
entity.Retain = input.Retain;
|
entity.Retain = input.Retain;
|
||||||
entity.Enabled = input.Enabled;
|
entity.Enabled = input.Enabled;
|
||||||
try { await db.SaveChangesAsync(ct); return new UnsMutationResult(true, null); }
|
|
||||||
catch (DbUpdateConcurrencyException) { return new UnsMutationResult(false, "Another user changed this scripted alarm while you were editing."); }
|
try
|
||||||
|
{
|
||||||
|
await db.SaveChangesAsync(ct);
|
||||||
|
return new UnsMutationResult(true, null);
|
||||||
|
}
|
||||||
|
catch (DbUpdateConcurrencyException)
|
||||||
|
{
|
||||||
|
return new UnsMutationResult(false, "Another user changed this scripted alarm while you were editing.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
@@ -1357,11 +1375,26 @@ public sealed class UnsTreeService(IDbContextFactory<OtOpcUaConfigDbContext> dbF
|
|||||||
{
|
{
|
||||||
await using var db = await dbFactory.CreateDbContextAsync(ct);
|
await using var db = await dbFactory.CreateDbContextAsync(ct);
|
||||||
var entity = await db.ScriptedAlarms.FirstOrDefaultAsync(a => a.ScriptedAlarmId == scriptedAlarmId, ct);
|
var entity = await db.ScriptedAlarms.FirstOrDefaultAsync(a => a.ScriptedAlarmId == scriptedAlarmId, ct);
|
||||||
if (entity is null) return new UnsMutationResult(true, null);
|
if (entity is null)
|
||||||
|
{
|
||||||
|
return new UnsMutationResult(true, null);
|
||||||
|
}
|
||||||
|
|
||||||
db.Entry(entity).Property(e => e.RowVersion).OriginalValue = rowVersion;
|
db.Entry(entity).Property(e => e.RowVersion).OriginalValue = rowVersion;
|
||||||
db.ScriptedAlarms.Remove(entity);
|
db.ScriptedAlarms.Remove(entity);
|
||||||
try { await db.SaveChangesAsync(ct); return new UnsMutationResult(true, null); }
|
|
||||||
catch (DbUpdateConcurrencyException) { return new UnsMutationResult(false, "Another user changed this alarm while you were viewing it."); }
|
try
|
||||||
catch (Exception ex) { return new UnsMutationResult(false, $"Delete failed: {ex.Message}."); }
|
{
|
||||||
|
await db.SaveChangesAsync(ct);
|
||||||
|
return new UnsMutationResult(true, null);
|
||||||
|
}
|
||||||
|
catch (DbUpdateConcurrencyException)
|
||||||
|
{
|
||||||
|
return new UnsMutationResult(false, "Another user changed this alarm while you were viewing it.");
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
return new UnsMutationResult(false, $"Delete failed: {ex.Message}.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -74,4 +74,16 @@ public sealed class UnsTreeServiceScriptedAlarmTests
|
|||||||
(await svc.DeleteScriptedAlarmAsync("SA-1", dto!.RowVersion)).Ok.ShouldBeTrue();
|
(await svc.DeleteScriptedAlarmAsync("SA-1", dto!.RowVersion)).Ok.ShouldBeTrue();
|
||||||
(await svc.LoadAlarmsForEquipmentAsync(UnsTreeTestDb.SeededEquipmentId)).ShouldBeEmpty();
|
(await svc.LoadAlarmsForEquipmentAsync(UnsTreeTestDb.SeededEquipmentId)).ShouldBeEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task Create_rejects_duplicate_name_on_same_equipment()
|
||||||
|
{
|
||||||
|
var svc = SeededService();
|
||||||
|
(await svc.CreateScriptedAlarmAsync(UnsTreeTestDb.SeededEquipmentId, Sample("SA-1"))).Ok.ShouldBeTrue();
|
||||||
|
// Same Name ("Over-temp" from Sample), different id, same equipment → rejected.
|
||||||
|
var dup = await svc.CreateScriptedAlarmAsync(UnsTreeTestDb.SeededEquipmentId, Sample("SA-2"));
|
||||||
|
dup.Ok.ShouldBeFalse();
|
||||||
|
dup.Error.ShouldNotBeNull();
|
||||||
|
dup.Error!.ShouldContain("already exists");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user