From f345a68c40784d6bb676063c3e18f76c1c2c4e04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Anders=20Chirico=20Indreb=C3=B8?= Date: Mon, 20 Jan 2025 14:28:55 +0100 Subject: [PATCH 1/7] Use readOnly everywhere --- backend/api.test/Services/RobotService.cs | 2 +- backend/api/Controllers/InspectionAreaController.cs | 2 +- backend/api/Controllers/MissionDefinitionController.cs | 4 ++-- backend/api/Services/InspectionService.cs | 4 ++-- backend/api/Services/MissionRunService.cs | 10 +++++----- backend/api/Services/MissionTaskService.cs | 2 +- backend/api/Services/UserInfoServices.cs | 4 ++-- 7 files changed, 14 insertions(+), 14 deletions(-) diff --git a/backend/api.test/Services/RobotService.cs b/backend/api.test/Services/RobotService.cs index 5d26c11e..6e4672b6 100644 --- a/backend/api.test/Services/RobotService.cs +++ b/backend/api.test/Services/RobotService.cs @@ -52,7 +52,7 @@ public async Task CheckThatReadByIdReturnsCorrectRobot() var installation = await DatabaseUtilities.NewInstallation(); var robot = await DatabaseUtilities.NewRobot(RobotStatus.Available, installation); - var robotById = await RobotService.ReadById(robot.Id, readOnly: false); + var robotById = await RobotService.ReadById(robot.Id, readOnly: true); Assert.Equal(robot.Id, robotById!.Id); } diff --git a/backend/api/Controllers/InspectionAreaController.cs b/backend/api/Controllers/InspectionAreaController.cs index 814eb183..6e52cadc 100644 --- a/backend/api/Controllers/InspectionAreaController.cs +++ b/backend/api/Controllers/InspectionAreaController.cs @@ -252,7 +252,7 @@ [FromBody] CreateDefaultLocalizationPose newDefaultLocalizationPose { var inspectionArea = await inspectionAreaService.ReadById( inspectionAreaId, - readOnly: false + readOnly: true ); if (inspectionArea is null) { diff --git a/backend/api/Controllers/MissionDefinitionController.cs b/backend/api/Controllers/MissionDefinitionController.cs index ba9b9f86..ff295a7c 100644 --- a/backend/api/Controllers/MissionDefinitionController.cs +++ b/backend/api/Controllers/MissionDefinitionController.cs @@ -147,7 +147,7 @@ [FromBody] UpdateMissionDefinitionQuery missionDefinitionQuery return BadRequest("Invalid data."); } - var missionDefinition = await missionDefinitionService.ReadById(id, readOnly: false); + var missionDefinition = await missionDefinitionService.ReadById(id, readOnly: true); if (missionDefinition == null) { return NotFound($"Could not find mission definition with id '{id}'"); @@ -198,7 +198,7 @@ [FromBody] UpdateMissionDefinitionIsDeprecatedQuery missionDefinitionIsDeprecate return BadRequest("Invalid data."); } - var missionDefinition = await missionDefinitionService.ReadById(id, readOnly: false); + var missionDefinition = await missionDefinitionService.ReadById(id, readOnly: true); if (missionDefinition == null) { return NotFound($"Could not find mission definition with id '{id}'"); diff --git a/backend/api/Services/InspectionService.cs b/backend/api/Services/InspectionService.cs index 7b8e2dbc..833a9b5d 100644 --- a/backend/api/Services/InspectionService.cs +++ b/backend/api/Services/InspectionService.cs @@ -60,7 +60,7 @@ public async Task UpdateInspectionStatus( IsarTaskStatus isarTaskStatus ) { - var inspection = await ReadByIsarTaskId(isarTaskId, readOnly: false); + var inspection = await ReadByIsarTaskId(isarTaskId, readOnly: true); if (inspection is null) { string errorMessage = $"Inspection with task ID {isarTaskId} could not be found"; @@ -136,7 +136,7 @@ private IQueryable GetInspections(bool readOnly = true) string isarTaskId ) { - var inspection = await ReadByIsarTaskId(isarTaskId, readOnly: false); + var inspection = await ReadByIsarTaskId(isarTaskId, readOnly: true); if (inspection is null) { diff --git a/backend/api/Services/MissionRunService.cs b/backend/api/Services/MissionRunService.cs index 4034543f..70c4184a 100644 --- a/backend/api/Services/MissionRunService.cs +++ b/backend/api/Services/MissionRunService.cs @@ -630,7 +630,7 @@ public async Task UpdateMissionRunType( MissionRunType missionRunType ) { - var missionRun = await ReadById(missionRunId, readOnly: false); + var missionRun = await ReadById(missionRunId, readOnly: true); if (missionRun is null) { string errorMessage = $"Mission with mission Id {missionRunId} was not found"; @@ -646,7 +646,7 @@ public async Task UpdateMissionRunStatusByIsarMissionId( MissionStatus missionStatus ) { - var missionRun = await ReadByIsarMissionId(isarMissionId, readOnly: false); + var missionRun = await ReadByIsarMissionId(isarMissionId, readOnly: true); if (missionRun is null) { string errorMessage = $"Mission with isar mission Id {isarMissionId} was not found"; @@ -682,7 +682,7 @@ public async Task UpdateMissionRunProperty( object? value ) { - var missionRun = await ReadById(missionRunId, readOnly: false); + var missionRun = await ReadById(missionRunId, readOnly: true); if (missionRun is null) { string errorMessage = @@ -754,7 +754,7 @@ string failureDescription ) { var missionRun = - await ReadById(missionRunId, readOnly: false) + await ReadById(missionRunId, readOnly: true) ?? throw new MissionRunNotFoundException( $"Could not find mission run with ID {missionRunId}" ); @@ -792,7 +792,7 @@ IsarMission isarMission ) { var missionRun = - await ReadById(missionRunId, readOnly: false) + await ReadById(missionRunId, readOnly: true) ?? throw new MissionRunNotFoundException( $"Could not find mission run with ID {missionRunId}" ); diff --git a/backend/api/Services/MissionTaskService.cs b/backend/api/Services/MissionTaskService.cs index 72ee2c75..2ad6866f 100644 --- a/backend/api/Services/MissionTaskService.cs +++ b/backend/api/Services/MissionTaskService.cs @@ -30,7 +30,7 @@ public async Task UpdateMissionTaskStatus( IsarTaskStatus isarTaskStatus ) { - var missionTask = await ReadByIsarTaskId(isarTaskId, readOnly: false); + var missionTask = await ReadByIsarTaskId(isarTaskId, readOnly: true); if (missionTask is null) { string errorMessage = $"Inspection with ID {isarTaskId} could not be found"; diff --git a/backend/api/Services/UserInfoServices.cs b/backend/api/Services/UserInfoServices.cs index 77559ea5..8824ad35 100644 --- a/backend/api/Services/UserInfoServices.cs +++ b/backend/api/Services/UserInfoServices.cs @@ -68,7 +68,7 @@ public async Task Update(UserInfo userInfo) public async Task Delete(string id) { - var userInfo = await GetUsersInfo(readOnly: false) + var userInfo = await GetUsersInfo(readOnly: true) .FirstOrDefaultAsync(ev => ev.Id.Equals(id)); if (userInfo is null) { @@ -92,7 +92,7 @@ public async Task Update(UserInfo userInfo) logger.LogWarning("User objectId is null so it will not be added to the database."); return null; } - var userInfo = await ReadByOid(objectId, readOnly: false); + var userInfo = await ReadByOid(objectId, readOnly: true); if (userInfo is null) { var newUserInfo = new UserInfo { Oid = objectId }; From 394f327451b22d8b80642ae21dafdd210c9119d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Anders=20Chirico=20Indreb=C3=B8?= Date: Mon, 20 Jan 2025 14:30:52 +0100 Subject: [PATCH 2/7] Add more ef entity detaching --- backend/api/Services/AreaService.cs | 1 + .../api/Services/DefaultLocalizationPoseService.cs | 1 + backend/api/Services/InspectionAreaService.cs | 1 + backend/api/Services/InspectionService.cs | 12 ++++++++++-- backend/api/Services/InstallationService.cs | 1 + backend/api/Services/MissionDefinitionService.cs | 1 + backend/api/Services/MissionTaskService.cs | 1 + backend/api/Services/PlantService.cs | 1 + backend/api/Services/RobotModelService.cs | 1 + 9 files changed, 18 insertions(+), 2 deletions(-) diff --git a/backend/api/Services/AreaService.cs b/backend/api/Services/AreaService.cs index c14ff8d7..a2a732af 100644 --- a/backend/api/Services/AreaService.cs +++ b/backend/api/Services/AreaService.cs @@ -218,6 +218,7 @@ public async Task Update(Area area) { var entry = context.Update(area); await ApplyDatabaseUpdate(area.Installation); + DetachTracking(area); return entry.Entity; } diff --git a/backend/api/Services/DefaultLocalizationPoseService.cs b/backend/api/Services/DefaultLocalizationPoseService.cs index 6058a9f3..c226e6a5 100644 --- a/backend/api/Services/DefaultLocalizationPoseService.cs +++ b/backend/api/Services/DefaultLocalizationPoseService.cs @@ -69,6 +69,7 @@ DefaultLocalizationPose defaultLocalizationPose { var entry = context.Update(defaultLocalizationPose); await context.SaveChangesAsync(); + DetachTracking(defaultLocalizationPose); return entry.Entity; } diff --git a/backend/api/Services/InspectionAreaService.cs b/backend/api/Services/InspectionAreaService.cs index f1190bb0..a0ef49b9 100644 --- a/backend/api/Services/InspectionAreaService.cs +++ b/backend/api/Services/InspectionAreaService.cs @@ -207,6 +207,7 @@ public async Task Update(InspectionArea inspectionArea) inspectionArea.Installation, new InspectionAreaResponse(inspectionArea) ); + DetachTracking(inspectionArea); return entry.Entity; } diff --git a/backend/api/Services/InspectionService.cs b/backend/api/Services/InspectionService.cs index 833a9b5d..587a8005 100644 --- a/backend/api/Services/InspectionService.cs +++ b/backend/api/Services/InspectionService.cs @@ -107,8 +107,7 @@ private async Task Update(Inspection inspection) var installation = missionRun?.InspectionArea?.Installation; await ApplyDatabaseUpdate(installation); - - return entry.Entity; + DetachTracking(inspection); } public async Task ReadByIsarTaskId(string id, bool readOnly = true) @@ -227,5 +226,14 @@ await response.Content.ReadFromJsonAsync() ); return null; } + + public void DetachTracking(Inspection inspection) + { + foreach (var inspectionFinding in inspection.InspectionFindings) + { + context.Entry(inspectionFinding).State = EntityState.Detached; + } + context.Entry(inspection).State = EntityState.Detached; + } } } diff --git a/backend/api/Services/InstallationService.cs b/backend/api/Services/InstallationService.cs index 76a1cbcb..37674b1e 100644 --- a/backend/api/Services/InstallationService.cs +++ b/backend/api/Services/InstallationService.cs @@ -119,6 +119,7 @@ public async Task Update(Installation installation) { var entry = context.Update(installation); await ApplyDatabaseUpdate(installation); + DetachTracking(installation); return entry.Entity; } diff --git a/backend/api/Services/MissionDefinitionService.cs b/backend/api/Services/MissionDefinitionService.cs index 4dfdedf5..a6ec055c 100644 --- a/backend/api/Services/MissionDefinitionService.cs +++ b/backend/api/Services/MissionDefinitionService.cs @@ -192,6 +192,7 @@ public async Task Update(MissionDefinition missionDefinition) missionDefinition?.InspectionArea?.Installation, missionDefinition != null ? new MissionDefinitionResponse(missionDefinition) : null ); + DetachTracking(missionDefinition!); return entry.Entity; } diff --git a/backend/api/Services/MissionTaskService.cs b/backend/api/Services/MissionTaskService.cs index 2ad6866f..143c8b54 100644 --- a/backend/api/Services/MissionTaskService.cs +++ b/backend/api/Services/MissionTaskService.cs @@ -49,6 +49,7 @@ private async Task Update(MissionTask missionTask) var entry = context.Update(missionTask); await context.SaveChangesAsync(); + DetachTracking(missionTask); return entry.Entity; } diff --git a/backend/api/Services/PlantService.cs b/backend/api/Services/PlantService.cs index 2c469887..bebcc46b 100644 --- a/backend/api/Services/PlantService.cs +++ b/backend/api/Services/PlantService.cs @@ -167,6 +167,7 @@ public async Task Update(Plant plant) { var entry = context.Update(plant); await ApplyDatabaseUpdate(plant.Installation); + DetachTracking(plant); return entry.Entity; } diff --git a/backend/api/Services/RobotModelService.cs b/backend/api/Services/RobotModelService.cs index 0cb01073..2c161543 100644 --- a/backend/api/Services/RobotModelService.cs +++ b/backend/api/Services/RobotModelService.cs @@ -84,6 +84,7 @@ public async Task Update(RobotModel robotModel) { var entry = _context.Update(robotModel); await _context.SaveChangesAsync(); + DetachTracking(robotModel); return entry.Entity; } From 7d472ce6245fbaf8a840c53f3707b39f7d5e229c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Anders=20Chirico=20Indreb=C3=B8?= Date: Mon, 20 Jan 2025 14:31:30 +0100 Subject: [PATCH 3/7] Avoid returning outdated models --- backend/api/Services/InspectionService.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/backend/api/Services/InspectionService.cs b/backend/api/Services/InspectionService.cs index 587a8005..1086c2c1 100644 --- a/backend/api/Services/InspectionService.cs +++ b/backend/api/Services/InspectionService.cs @@ -69,7 +69,7 @@ IsarTaskStatus isarTaskStatus } inspection.UpdateStatus(isarTaskStatus); - inspection = await Update(inspection); + await Update(inspection); return inspection; } @@ -89,7 +89,7 @@ private async Task ApplyDatabaseUpdate(Installation? installation) ); } - private async Task Update(Inspection inspection) + private async Task Update(Inspection inspection) { var entry = context.Update(inspection); @@ -150,7 +150,7 @@ string isarTaskId }; inspection.InspectionFindings.Add(inspectionFinding); - inspection = await Update(inspection); + await Update(inspection); return inspection; } From 853bee8c28cd3c1b635ecab4d06b7c303281f4f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Anders=20Chirico=20Indreb=C3=B8?= Date: Mon, 20 Jan 2025 16:08:33 +0100 Subject: [PATCH 4/7] Pass context into DetachTracking --- backend/api/Services/AccessRoleService.cs | 6 ++-- backend/api/Services/AreaService.cs | 19 ++++++----- .../DefaultLocalizationPoseService.cs | 14 +++++--- backend/api/Services/InspectionAreaService.cs | 29 +++++++++++------ backend/api/Services/InspectionService.cs | 4 +-- backend/api/Services/InstallationService.cs | 8 ++--- .../api/Services/MissionDefinitionService.cs | 12 +++---- backend/api/Services/MissionRunService.cs | 27 ++++++++++------ backend/api/Services/MissionTaskService.cs | 6 ++-- backend/api/Services/PlantService.cs | 10 +++--- backend/api/Services/RobotModelService.cs | 8 ++--- backend/api/Services/RobotService.cs | 32 +++++++++++-------- backend/api/Services/SourceService.cs | 8 ++--- 13 files changed, 108 insertions(+), 75 deletions(-) diff --git a/backend/api/Services/AccessRoleService.cs b/backend/api/Services/AccessRoleService.cs index 7da9bd20..ec6c9f1e 100644 --- a/backend/api/Services/AccessRoleService.cs +++ b/backend/api/Services/AccessRoleService.cs @@ -18,7 +18,7 @@ RoleAccessLevel accessLevel ); public Task ReadByInstallation(Installation installation); public Task> ReadAll(); - public void DetachTracking(AccessRole accessRole); + public void DetachTracking(FlotillaDbContext context, AccessRole accessRole); } public class AccessRoleService( @@ -101,7 +101,7 @@ RoleAccessLevel accessLevel await context.AccessRoles.AddAsync(newAccessRole); await context.SaveChangesAsync(); - DetachTracking(newAccessRole); + DetachTracking(context, newAccessRole); return newAccessRole!; } @@ -135,7 +135,7 @@ public bool IsAuthenticationAvailable() return httpContextAccessor.HttpContext != null; } - public void DetachTracking(AccessRole accessRole) + public void DetachTracking(FlotillaDbContext context, AccessRole accessRole) { context.Entry(accessRole).State = EntityState.Detached; } diff --git a/backend/api/Services/AreaService.cs b/backend/api/Services/AreaService.cs index a2a732af..05bd3c40 100644 --- a/backend/api/Services/AreaService.cs +++ b/backend/api/Services/AreaService.cs @@ -35,7 +35,7 @@ public Task> ReadAll( public Task Delete(string id); - public void DetachTracking(Area area); + public void DetachTracking(FlotillaDbContext context, Area area); } [SuppressMessage( @@ -210,7 +210,7 @@ await inspectionAreaService.ReadByInstallationAndPlantAndName( await context.Areas.AddAsync(newArea); await ApplyDatabaseUpdate(installation); - DetachTracking(newArea); + DetachTracking(context, newArea); return newArea; } @@ -218,7 +218,7 @@ public async Task Update(Area area) { var entry = context.Update(area); await ApplyDatabaseUpdate(area.Installation); - DetachTracking(area); + DetachTracking(context, area); return entry.Entity; } @@ -353,16 +353,19 @@ AreaQueryStringParameters parameters return Expression.Lambda>(body, area); } - public void DetachTracking(Area area) + public void DetachTracking(FlotillaDbContext context, Area area) { if (area.Installation != null) - installationService.DetachTracking(area.Installation); + installationService.DetachTracking(context, area.Installation); if (area.Plant != null) - plantService.DetachTracking(area.Plant); + plantService.DetachTracking(context, area.Plant); if (area.InspectionArea != null) - inspectionAreaService.DetachTracking(area.InspectionArea); + inspectionAreaService.DetachTracking(context, area.InspectionArea); if (area.DefaultLocalizationPose != null) - defaultLocalizationPoseService.DetachTracking(area.DefaultLocalizationPose); + defaultLocalizationPoseService.DetachTracking( + context, + area.DefaultLocalizationPose + ); context.Entry(area).State = EntityState.Detached; } } diff --git a/backend/api/Services/DefaultLocalizationPoseService.cs b/backend/api/Services/DefaultLocalizationPoseService.cs index c226e6a5..8202ec0d 100644 --- a/backend/api/Services/DefaultLocalizationPoseService.cs +++ b/backend/api/Services/DefaultLocalizationPoseService.cs @@ -21,7 +21,10 @@ DefaultLocalizationPose defaultLocalizationPose public abstract Task Delete(string id); - public void DetachTracking(DefaultLocalizationPose defaultLocalizationPose); + public void DetachTracking( + FlotillaDbContext context, + DefaultLocalizationPose defaultLocalizationPose + ); } [System.Diagnostics.CodeAnalysis.SuppressMessage( @@ -59,7 +62,7 @@ DefaultLocalizationPose defaultLocalizationPose await context.DefaultLocalizationPoses.AddAsync(defaultLocalizationPose); await context.SaveChangesAsync(); - DetachTracking(defaultLocalizationPose); + DetachTracking(context, defaultLocalizationPose); return defaultLocalizationPose; } @@ -69,7 +72,7 @@ DefaultLocalizationPose defaultLocalizationPose { var entry = context.Update(defaultLocalizationPose); await context.SaveChangesAsync(); - DetachTracking(defaultLocalizationPose); + DetachTracking(context, defaultLocalizationPose); return entry.Entity; } @@ -88,7 +91,10 @@ DefaultLocalizationPose defaultLocalizationPose return defaultLocalizationPose; } - public void DetachTracking(DefaultLocalizationPose defaultLocalizationPose) + public void DetachTracking( + FlotillaDbContext context, + DefaultLocalizationPose defaultLocalizationPose + ) { context.Entry(defaultLocalizationPose).State = EntityState.Detached; } diff --git a/backend/api/Services/InspectionAreaService.cs b/backend/api/Services/InspectionAreaService.cs index a0ef49b9..408ee3f5 100644 --- a/backend/api/Services/InspectionAreaService.cs +++ b/backend/api/Services/InspectionAreaService.cs @@ -38,7 +38,7 @@ public Task> ReadByInstallation( public Task Delete(string id); - public void DetachTracking(InspectionArea inspectionArea); + public void DetachTracking(FlotillaDbContext context, InspectionArea inspectionArea); } [SuppressMessage( @@ -194,7 +194,7 @@ await plantService.ReadByInstallationAndPlantCode( inspectionArea.Installation, new InspectionAreaResponse(inspectionArea) ); - DetachTracking(inspectionArea); + DetachTracking(context, inspectionArea); return inspectionArea!; } @@ -207,7 +207,7 @@ public async Task Update(InspectionArea inspectionArea) inspectionArea.Installation, new InspectionAreaResponse(inspectionArea) ); - DetachTracking(inspectionArea); + DetachTracking(context, inspectionArea); return entry.Entity; } @@ -264,14 +264,25 @@ private async Task ApplyDatabaseUpdate(Installation? installation) ); } - public void DetachTracking(InspectionArea inspectionArea) + public void DetachTracking(FlotillaDbContext context, InspectionArea inspectionArea) { - if (inspectionArea.Installation != null) - installationService.DetachTracking(inspectionArea.Installation); - if (inspectionArea.Plant != null) - plantService.DetachTracking(inspectionArea.Plant); - if (inspectionArea.DefaultLocalizationPose != null) + if ( + inspectionArea.Installation != null + && context.Entry(inspectionArea.Installation).State != EntityState.Detached + ) + installationService.DetachTracking(context, inspectionArea.Installation); + if ( + inspectionArea.Plant != null + && context.Entry(inspectionArea.Plant).State != EntityState.Detached + ) + plantService.DetachTracking(context, inspectionArea.Plant); + if ( + inspectionArea.DefaultLocalizationPose != null + && context.Entry(inspectionArea.DefaultLocalizationPose).State + != EntityState.Detached + ) defaultLocalizationPoseService.DetachTracking( + context, inspectionArea.DefaultLocalizationPose ); context.Entry(inspectionArea).State = EntityState.Detached; diff --git a/backend/api/Services/InspectionService.cs b/backend/api/Services/InspectionService.cs index 1086c2c1..61ad6805 100644 --- a/backend/api/Services/InspectionService.cs +++ b/backend/api/Services/InspectionService.cs @@ -107,7 +107,7 @@ private async Task Update(Inspection inspection) var installation = missionRun?.InspectionArea?.Installation; await ApplyDatabaseUpdate(installation); - DetachTracking(inspection); + DetachTracking(context, inspection); } public async Task ReadByIsarTaskId(string id, bool readOnly = true) @@ -227,7 +227,7 @@ await response.Content.ReadFromJsonAsync() return null; } - public void DetachTracking(Inspection inspection) + public void DetachTracking(FlotillaDbContext context, Inspection inspection) { foreach (var inspectionFinding in inspection.InspectionFindings) { diff --git a/backend/api/Services/InstallationService.cs b/backend/api/Services/InstallationService.cs index 37674b1e..721e46ff 100644 --- a/backend/api/Services/InstallationService.cs +++ b/backend/api/Services/InstallationService.cs @@ -23,7 +23,7 @@ public interface IInstallationService public abstract Task Delete(string id); - public void DetachTracking(Installation installation); + public void DetachTracking(FlotillaDbContext context, Installation installation); } [System.Diagnostics.CodeAnalysis.SuppressMessage( @@ -109,7 +109,7 @@ public async Task Create(CreateInstallationQuery newInstallationQu }; await context.Installations.AddAsync(installation); await ApplyUnprotectedDatabaseUpdate(); - DetachTracking(installation); + DetachTracking(context, installation); } return installation; @@ -119,7 +119,7 @@ public async Task Update(Installation installation) { var entry = context.Update(installation); await ApplyDatabaseUpdate(installation); - DetachTracking(installation); + DetachTracking(context, installation); return entry.Entity; } @@ -137,7 +137,7 @@ public async Task Update(Installation installation) return installation; } - public void DetachTracking(Installation installation) + public void DetachTracking(FlotillaDbContext context, Installation installation) { context.Entry(installation).State = EntityState.Detached; } diff --git a/backend/api/Services/MissionDefinitionService.cs b/backend/api/Services/MissionDefinitionService.cs index a6ec055c..e05e952d 100644 --- a/backend/api/Services/MissionDefinitionService.cs +++ b/backend/api/Services/MissionDefinitionService.cs @@ -39,7 +39,7 @@ string missionDefinitionId public Task Delete(string id); - public void DetachTracking(MissionDefinition missionDefinition); + public void DetachTracking(FlotillaDbContext context, MissionDefinition missionDefinition); } [SuppressMessage( @@ -84,7 +84,7 @@ public async Task Create(MissionDefinition missionDefinition) missionDefinition.InspectionArea?.Installation, new MissionDefinitionResponse(missionDefinition) ); - DetachTracking(missionDefinition); + DetachTracking(context, missionDefinition); return missionDefinition; } @@ -192,7 +192,7 @@ public async Task Update(MissionDefinition missionDefinition) missionDefinition?.InspectionArea?.Installation, missionDefinition != null ? new MissionDefinitionResponse(missionDefinition) : null ); - DetachTracking(missionDefinition!); + DetachTracking(context, missionDefinition!); return entry.Entity; } @@ -328,12 +328,12 @@ parameters.InstallationCode is null ); } - public void DetachTracking(MissionDefinition missionDefinition) + public void DetachTracking(FlotillaDbContext context, MissionDefinition missionDefinition) { if (missionDefinition.LastSuccessfulRun != null) - missionRunService.DetachTracking(missionDefinition.LastSuccessfulRun); + missionRunService.DetachTracking(context, missionDefinition.LastSuccessfulRun); if (missionDefinition.Source != null) - sourceService.DetachTracking(missionDefinition.Source); + sourceService.DetachTracking(context, missionDefinition.Source); context.Entry(missionDefinition).State = EntityState.Detached; } } diff --git a/backend/api/Services/MissionRunService.cs b/backend/api/Services/MissionRunService.cs index 70c4184a..2ad60f09 100644 --- a/backend/api/Services/MissionRunService.cs +++ b/backend/api/Services/MissionRunService.cs @@ -88,7 +88,7 @@ string failureDescription public Task UpdateCurrentRobotMissionToFailed(string robotId); - public void DetachTracking(MissionRun missionRun); + public void DetachTracking(FlotillaDbContext context, MissionRun missionRun); } [SuppressMessage( @@ -143,7 +143,7 @@ public async Task Create( new MissionRunResponse(missionRun) ); - DetachTracking(missionRun); + DetachTracking(context, missionRun); if (triggerCreatedMissionRunEvent) { @@ -311,7 +311,7 @@ public async Task Update(MissionRun missionRun) missionRun?.InspectionArea?.Installation, missionRun != null ? new MissionRunResponse(missionRun) : null ); - DetachTracking(missionRun!); + DetachTracking(context, missionRun!); return entry.Entity; } @@ -773,17 +773,24 @@ await ReadById(missionRunId, readOnly: true) return await Update(missionRun); } - public void DetachTracking(MissionRun missionRun) + public void DetachTracking(FlotillaDbContext context, MissionRun missionRun) { + context.Entry(missionRun).State = EntityState.Detached; foreach (var task in missionRun.Tasks) { - missionTaskService.DetachTracking(task); + if (context.Entry(task).State != EntityState.Detached) + missionTaskService.DetachTracking(context, task); } - if (missionRun.InspectionArea != null) - inspectionAreaService.DetachTracking(missionRun.InspectionArea); - if (missionRun.Robot != null) - robotService.DetachTracking(missionRun.Robot); - context.Entry(missionRun).State = EntityState.Detached; + if ( + missionRun.InspectionArea != null + && context.Entry(missionRun.InspectionArea).State != EntityState.Detached + ) + inspectionAreaService.DetachTracking(context, missionRun.InspectionArea); + if ( + missionRun.Robot != null + && context.Entry(missionRun.Robot).State != EntityState.Detached + ) + robotService.DetachTracking(context, missionRun.Robot); } public async Task UpdateWithIsarInfo( diff --git a/backend/api/Services/MissionTaskService.cs b/backend/api/Services/MissionTaskService.cs index 143c8b54..8a240dd5 100644 --- a/backend/api/Services/MissionTaskService.cs +++ b/backend/api/Services/MissionTaskService.cs @@ -14,7 +14,7 @@ public Task UpdateMissionTaskStatus( IsarTaskStatus isarTaskStatus ); - public void DetachTracking(MissionTask missionTask); + public void DetachTracking(FlotillaDbContext context, MissionTask missionTask); } [SuppressMessage( @@ -49,7 +49,7 @@ private async Task Update(MissionTask missionTask) var entry = context.Update(missionTask); await context.SaveChangesAsync(); - DetachTracking(missionTask); + DetachTracking(context, missionTask); return entry.Entity; } @@ -72,7 +72,7 @@ private IQueryable GetMissionTasks(bool readOnly = true) ); } - public void DetachTracking(MissionTask missionTask) + public void DetachTracking(FlotillaDbContext context, MissionTask missionTask) { context.Entry(missionTask).State = EntityState.Detached; } diff --git a/backend/api/Services/PlantService.cs b/backend/api/Services/PlantService.cs index bebcc46b..c4f3d23c 100644 --- a/backend/api/Services/PlantService.cs +++ b/backend/api/Services/PlantService.cs @@ -39,7 +39,7 @@ public Task> ReadByInstallation( public Task Delete(string id); - public void DetachTracking(Plant plant); + public void DetachTracking(FlotillaDbContext context, Plant plant); } [SuppressMessage( @@ -158,7 +158,7 @@ await installationService.ReadByInstallationCode( context.Entry(plant.Installation).State = EntityState.Unchanged; await context.Plants.AddAsync(plant); await ApplyDatabaseUpdate(plant.Installation); - DetachTracking(plant); + DetachTracking(context, plant); } return plant!; } @@ -167,7 +167,7 @@ public async Task Update(Plant plant) { var entry = context.Update(plant); await ApplyDatabaseUpdate(plant.Installation); - DetachTracking(plant); + DetachTracking(context, plant); return entry.Entity; } @@ -215,10 +215,10 @@ private async Task ApplyDatabaseUpdate(Installation? installation) ); } - public void DetachTracking(Plant plant) + public void DetachTracking(FlotillaDbContext context, Plant plant) { if (plant.Installation != null) - installationService.DetachTracking(plant.Installation); + installationService.DetachTracking(context, plant.Installation); context.Entry(plant).State = EntityState.Detached; } } diff --git a/backend/api/Services/RobotModelService.cs b/backend/api/Services/RobotModelService.cs index 2c161543..f66612a2 100644 --- a/backend/api/Services/RobotModelService.cs +++ b/backend/api/Services/RobotModelService.cs @@ -21,7 +21,7 @@ public interface IRobotModelService public abstract Task Delete(string id); - public void DetachTracking(RobotModel robotModel); + public void DetachTracking(FlotillaDbContext context, RobotModel robotModel); } [System.Diagnostics.CodeAnalysis.SuppressMessage( @@ -76,7 +76,7 @@ public async Task Create(RobotModel newRobotModel) { await _context.RobotModels.AddAsync(newRobotModel); await _context.SaveChangesAsync(); - DetachTracking(newRobotModel); + DetachTracking(_context, newRobotModel); return newRobotModel; } @@ -84,7 +84,7 @@ public async Task Update(RobotModel robotModel) { var entry = _context.Update(robotModel); await _context.SaveChangesAsync(); - DetachTracking(robotModel); + DetachTracking(_context, robotModel); return entry.Entity; } @@ -102,7 +102,7 @@ public async Task Update(RobotModel robotModel) return robotModel; } - public void DetachTracking(RobotModel robotModel) + public void DetachTracking(FlotillaDbContext context, RobotModel robotModel) { _context.Entry(robotModel).State = EntityState.Detached; } diff --git a/backend/api/Services/RobotService.cs b/backend/api/Services/RobotService.cs index 56d2ff7b..6d13b85c 100644 --- a/backend/api/Services/RobotService.cs +++ b/backend/api/Services/RobotService.cs @@ -35,7 +35,7 @@ public Task> ReadRobotsForInstallation( public Task UpdateMissionQueueFrozen(string robotId, bool missionQueueFrozen); public Task UpdateFlotillaStatus(string robotId, RobotFlotillaStatus status); public Task Delete(string id); - public void DetachTracking(Robot robot); + public void DetachTracking(FlotillaDbContext context, Robot robot); } [SuppressMessage( @@ -64,7 +64,7 @@ public async Task Create(Robot newRobot) await context.Robots.AddAsync(newRobot); await ApplyDatabaseUpdate(newRobot.CurrentInstallation); - DetachTracking(newRobot); + DetachTracking(context, newRobot); return newRobot; } @@ -128,7 +128,7 @@ public async Task CreateFromQuery(CreateRobotQuery robotQuery) newRobot!.CurrentInstallation, new RobotResponse(newRobot!) ); - DetachTracking(newRobot); + DetachTracking(context, newRobot); return newRobot!; } throw new DbUpdateException( @@ -223,7 +223,7 @@ await robotQuery robot = await robotQuery.FirstOrDefaultAsync(); ThrowIfRobotIsNull(robot, robotId); NotifySignalROfUpdatedRobot(robot!, robot!.CurrentInstallation!); - DetachTracking(robot); + DetachTracking(context, robot); } public async Task UpdateRobotIsarConnected(string robotId, bool isarConnected) @@ -318,7 +318,7 @@ public async Task Update(Robot robot) robot?.CurrentInstallation, robot != null ? new RobotResponse(robot) : null ); - DetachTracking(robot!); + DetachTracking(context, robot!); } public async Task Delete(string id) @@ -433,7 +433,7 @@ private async Task UpdateRobotProperty( logger.LogError(e, "Failed to update {robotName}", robot.Name); } ; - DetachTracking(robot); + DetachTracking(context, robot); } private async Task ApplyDatabaseUpdate(Installation? installation) @@ -479,15 +479,21 @@ private void NotifySignalROfUpdatedRobot(Robot robot, Installation installation) ); } - public void DetachTracking(Robot robot) + public void DetachTracking(FlotillaDbContext context, Robot robot) { - if (robot.CurrentInstallation != null) - installationService.DetachTracking(robot.CurrentInstallation); - if (robot.CurrentInspectionArea != null) - inspectionAreaService.DetachTracking(robot.CurrentInspectionArea); - if (robot.Model != null) - robotModelService.DetachTracking(robot.Model); context.Entry(robot).State = EntityState.Detached; + if ( + robot.CurrentInstallation != null + && context.Entry(robot.CurrentInstallation).State != EntityState.Detached + ) + installationService.DetachTracking(context, robot.CurrentInstallation); + if ( + robot.CurrentInspectionArea != null + && context.Entry(robot.CurrentInspectionArea).State != EntityState.Detached + ) + inspectionAreaService.DetachTracking(context, robot.CurrentInspectionArea); + if (robot.Model != null && context.Entry(robot.Model).State != EntityState.Detached) + robotModelService.DetachTracking(context, robot.Model); } } } diff --git a/backend/api/Services/SourceService.cs b/backend/api/Services/SourceService.cs index 951b9654..6be6f77b 100644 --- a/backend/api/Services/SourceService.cs +++ b/backend/api/Services/SourceService.cs @@ -27,7 +27,7 @@ public abstract Task CreateSourceIfDoesNotExist( public abstract Task Delete(string id); - public void DetachTracking(Source source); + public void DetachTracking(FlotillaDbContext context, Source source); } [System.Diagnostics.CodeAnalysis.SuppressMessage( @@ -42,7 +42,7 @@ public async Task Create(Source source) { context.Sources.Add(source); await context.SaveChangesAsync(); - DetachTracking(source); + DetachTracking(context, source); return source; } @@ -128,7 +128,7 @@ public async Task CreateSourceIfDoesNotExist( var newSource = await Create(new Source { SourceId = hash, CustomMissionTasks = json }); - DetachTracking(newSource); + DetachTracking(context, newSource); return newSource; } @@ -146,7 +146,7 @@ public async Task CreateSourceIfDoesNotExist( return source; } - public void DetachTracking(Source source) + public void DetachTracking(FlotillaDbContext context, Source source) { context.Entry(source).State = EntityState.Detached; } From b981a05805229b830c010f8260faf8cce3ef2231 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Anders=20Chirico=20Indreb=C3=B8?= Date: Tue, 21 Jan 2025 09:42:52 +0100 Subject: [PATCH 5/7] Avoid reading in robot object again --- .../api/Services/MissionSchedulingService.cs | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/backend/api/Services/MissionSchedulingService.cs b/backend/api/Services/MissionSchedulingService.cs index 6eafcfca..a0a27ecb 100644 --- a/backend/api/Services/MissionSchedulingService.cs +++ b/backend/api/Services/MissionSchedulingService.cs @@ -524,20 +524,10 @@ await missionRunService.Create( private async Task StartMissionRun(MissionRun queuedMissionRun, Robot robot) { - string missionRunId = queuedMissionRun.Id; - - var missionRun = await missionRunService.ReadById(missionRunId, readOnly: true); - if (missionRun == null) - { - string errorMessage = $"Could not find mission run with id {missionRunId}"; - logger.LogError("{Message}", errorMessage); - throw new MissionRunNotFoundException(errorMessage); - } - IsarMission isarMission; try { - isarMission = await isarService.StartMission(robot, missionRun); + isarMission = await isarService.StartMission(robot, queuedMissionRun); } catch (HttpRequestException e) { @@ -559,16 +549,16 @@ private async Task StartMissionRun(MissionRun queuedMissionRun, Robot robot) throw new IsarCommunicationException(ErrorMessage); } - await missionRunService.UpdateWithIsarInfo(missionRun.Id, isarMission); + await missionRunService.UpdateWithIsarInfo(queuedMissionRun.Id, isarMission); await missionRunService.UpdateMissionRunProperty( - missionRun.Id, + queuedMissionRun.Id, "Status", MissionStatus.Ongoing ); robot.Status = RobotStatus.Busy; await robotService.UpdateRobotStatus(robot.Id, RobotStatus.Busy); - await robotService.UpdateCurrentMissionId(robot.Id, missionRun.Id); + await robotService.UpdateCurrentMissionId(robot.Id, queuedMissionRun.Id); logger.LogInformation("Started mission run '{Id}'", queuedMissionRun.Id); } From e45415deec70b17cc683318e1dd37879326ad06f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Anders=20Chirico=20Indreb=C3=B8?= Date: Tue, 21 Jan 2025 09:44:31 +0100 Subject: [PATCH 6/7] Detach and attach tracking on inspection correctly --- backend/api/Services/MissionRunService.cs | 10 +++++++++- backend/api/Services/MissionTaskService.cs | 2 ++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/backend/api/Services/MissionRunService.cs b/backend/api/Services/MissionRunService.cs index 2ad60f09..1ebbdb57 100644 --- a/backend/api/Services/MissionRunService.cs +++ b/backend/api/Services/MissionRunService.cs @@ -298,11 +298,19 @@ public bool IncludesUnsupportedInspectionType(MissionRun missionRun) public async Task Update(MissionRun missionRun) { - context.Entry(missionRun.Robot).State = EntityState.Unchanged; + if (missionRun.Robot is not null) + { + context.Entry(missionRun.Robot).State = EntityState.Unchanged; + } if (missionRun.InspectionArea is not null) { context.Entry(missionRun.InspectionArea).State = EntityState.Unchanged; } + foreach (var task in missionRun.Tasks) + { + if (task.Inspection != null) + context.Entry(task.Inspection).State = EntityState.Unchanged; + } var entry = context.Update(missionRun); await ApplyDatabaseUpdate(missionRun.InspectionArea?.Installation); diff --git a/backend/api/Services/MissionTaskService.cs b/backend/api/Services/MissionTaskService.cs index 8a240dd5..61e9a6a9 100644 --- a/backend/api/Services/MissionTaskService.cs +++ b/backend/api/Services/MissionTaskService.cs @@ -75,6 +75,8 @@ private IQueryable GetMissionTasks(bool readOnly = true) public void DetachTracking(FlotillaDbContext context, MissionTask missionTask) { context.Entry(missionTask).State = EntityState.Detached; + if (missionTask.Inspection != null) + context.Entry(missionTask.Inspection).State = EntityState.Detached; } } } From b23cd236a10cd3f604c91c28b2145de2abc20bda Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Anders=20Chirico=20Indreb=C3=B8?= Date: Tue, 21 Jan 2025 11:01:52 +0100 Subject: [PATCH 7/7] Fix incorrect updating of missionStatus --- .../api/EventHandlers/MissionEventHandler.cs | 8 ++++++++ backend/api/EventHandlers/MqttEventHandler.cs | 2 +- backend/api/Services/MissionRunService.cs | 17 +++++++---------- 3 files changed, 16 insertions(+), 11 deletions(-) diff --git a/backend/api/EventHandlers/MissionEventHandler.cs b/backend/api/EventHandlers/MissionEventHandler.cs index 10d06fa2..26b00259 100644 --- a/backend/api/EventHandlers/MissionEventHandler.cs +++ b/backend/api/EventHandlers/MissionEventHandler.cs @@ -89,6 +89,14 @@ private async void OnMissionRunCreated(object? sender, MissionRunCreatedEventArg private async void OnRobotAvailable(object? sender, RobotAvailableEventArgs e) { + if (e.Robot.Status != RobotStatus.Available) + { + _logger.LogWarning( + "OnRobotAvailable was triggered while robot was {robotStatus}", + e.Robot.Status + ); + return; + } _startMissionSemaphore.WaitOne(); try { diff --git a/backend/api/EventHandlers/MqttEventHandler.cs b/backend/api/EventHandlers/MqttEventHandler.cs index 880e20b8..8d8f0e90 100644 --- a/backend/api/EventHandlers/MqttEventHandler.cs +++ b/backend/api/EventHandlers/MqttEventHandler.cs @@ -454,7 +454,7 @@ await MissionRunService.UpdateMissionRunStatusByIsarMissionId( if (updatedFlotillaMissionRun.MissionId == null) { _logger.LogInformation( - "Mission run {missionRunId} does not have a mission definition assosiated with it", + "Mission run {missionRunId} does not have a mission definition associated with it", updatedFlotillaMissionRun.Id ); return; diff --git a/backend/api/Services/MissionRunService.cs b/backend/api/Services/MissionRunService.cs index 1ebbdb57..dfb889e5 100644 --- a/backend/api/Services/MissionRunService.cs +++ b/backend/api/Services/MissionRunService.cs @@ -296,7 +296,7 @@ public bool IncludesUnsupportedInspectionType(MissionRun missionRun) ); } - public async Task Update(MissionRun missionRun) + public async Task Update(MissionRun missionRun) { if (missionRun.Robot is not null) { @@ -320,7 +320,6 @@ public async Task Update(MissionRun missionRun) missionRun != null ? new MissionRunResponse(missionRun) : null ); DetachTracking(context, missionRun!); - return entry.Entity; } public async Task Delete(string id) @@ -664,11 +663,7 @@ MissionStatus missionStatus missionRun.Status = missionStatus; - missionRun = await UpdateMissionRunProperty( - missionRun.Id, - "MissionStatus", - missionStatus - ); + missionRun = await UpdateMissionRunProperty(missionRun.Id, "Status", missionStatus); if (missionRun.Status == MissionStatus.Failed) { @@ -716,7 +711,7 @@ public async Task UpdateMissionRunProperty( try { - missionRun = await Update(missionRun); + await Update(missionRun); } catch (InvalidOperationException e) { @@ -778,7 +773,8 @@ await ReadById(missionRunId, readOnly: true) task.Inspection.Status = InspectionStatus.Failed; } } - return await Update(missionRun); + await Update(missionRun); + return missionRun; } public void DetachTracking(FlotillaDbContext context, MissionRun missionRun) @@ -818,7 +814,8 @@ await ReadById(missionRunId, readOnly: true) var task = missionRun.GetTaskByIsarId(isarTask.IsarTaskId); task?.UpdateWithIsarInfo(isarTask); } - return await Update(missionRun); + await Update(missionRun); + return missionRun; } } }