365 lines
14 KiB
Markdown
365 lines
14 KiB
Markdown
|
|
---
|
||
|
|
source_files:
|
||
|
|
- Common/DTS.Common.Import/Persist/SaveServer.cs
|
||
|
|
- Common/DTS.Common.Import/Persist/SaveGroupTemplates.cs
|
||
|
|
- Common/DTS.Common.Import/Persist/SaveVariantBase.cs
|
||
|
|
- Common/DTS.Common.Import/Persist/SaveGlobalSettings.cs
|
||
|
|
- Common/DTS.Common.Import/Persist/PersistCalculator.cs
|
||
|
|
- Common/DTS.Common.Import/Persist/SaveSensorModels.cs
|
||
|
|
- Common/DTS.Common.Import/Persist/SaveTestEngineerDetails.cs
|
||
|
|
- Common/DTS.Common.Import/Persist/SaveLabDetails.cs
|
||
|
|
- Common/DTS.Common.Import/Persist/SaveUsers.cs
|
||
|
|
- Common/DTS.Common.Import/Persist/SaveCustomerDetails.cs
|
||
|
|
- Common/DTS.Common.Import/Persist/SaveHardware.cs
|
||
|
|
- Common/DTS.Common.Import/Persist/SaveTestSetupHelper.cs
|
||
|
|
- Common/DTS.Common.Import/Persist/SaveGroups.cs
|
||
|
|
- Common/DTS.Common.Import/Persist/SaveCustomChannels.cs
|
||
|
|
- Common/DTS.Common.Import/Persist/SaveTestSetup.cs
|
||
|
|
- Common/DTS.Common.Import/Persist/SaveCheckoutTestSetup.cs
|
||
|
|
generated_at: "2026-04-17T15:28:30.641712+00:00"
|
||
|
|
model: "zai-org/GLM-5-FP8"
|
||
|
|
schema_version: 1
|
||
|
|
sha256: "85e93f86bc467691"
|
||
|
|
---
|
||
|
|
|
||
|
|
# DTS.Common.Import.Persist Module Documentation
|
||
|
|
|
||
|
|
## 1. Purpose
|
||
|
|
|
||
|
|
This module implements the persistence layer for importing various data entities into the DTS (Data Test System). It provides a Strategy pattern implementation where each `SaveVariantBase` subclass handles persisting a specific entity type (hardware, users, test setups, groups, sensors, etc.) to the database. The module coordinates progress tracking, cancellation support, and ID remapping between old imported identifiers and newly assigned database identifiers.
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 2. Public Interface
|
||
|
|
|
||
|
|
### SaveVariantBase (Abstract Base Class)
|
||
|
|
```csharp
|
||
|
|
public abstract class SaveVariantBase : IPersistImport
|
||
|
|
{
|
||
|
|
protected ImportObject _importObject;
|
||
|
|
protected readonly IPersistCalculator _persistCalculator;
|
||
|
|
protected readonly IImportNotification _importNotification;
|
||
|
|
protected readonly Func<bool> IsCancelled;
|
||
|
|
|
||
|
|
protected SaveVariantBase(ImportObject importObject, IPersistCalculator persistCalculator,
|
||
|
|
IImportNotification importNotification, Func<bool> isCancelled = null)
|
||
|
|
|
||
|
|
public abstract void Save();
|
||
|
|
}
|
||
|
|
```
|
||
|
|
Base class for all save variants. Provides shared infrastructure for progress notification and cancellation.
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
### PersistCalculator
|
||
|
|
```csharp
|
||
|
|
public class PersistCalculator : IPersistCalculator
|
||
|
|
{
|
||
|
|
public double ProgressValue { get; } // Returns _done / _total
|
||
|
|
|
||
|
|
public void AddDone() // Increments _done by 1
|
||
|
|
public void AddDone(double value) // Increments _done by value
|
||
|
|
public void AddToTotal(double value) // Adds to _total (throws if value < 0)
|
||
|
|
}
|
||
|
|
```
|
||
|
|
Calculates import progress as a ratio of completed work to total work.
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
### SaveHardware
|
||
|
|
```csharp
|
||
|
|
public class SaveHardware : SaveVariantBase
|
||
|
|
{
|
||
|
|
public Dictionary<int, int> OldDASIdToNewDASId { get; set; }
|
||
|
|
public Dictionary<int, List<IISOHardware>> TestIdToHardware { get; set; }
|
||
|
|
|
||
|
|
public SaveHardware(ImportObject importObject, IPersistCalculator persistCalculator,
|
||
|
|
IImportNotification importNotification, Func<bool> isCancelled = null)
|
||
|
|
|
||
|
|
public override void Save()
|
||
|
|
}
|
||
|
|
```
|
||
|
|
Persists hardware entities. Tracks DAS ID remapping and hardware-to-test relationships for downstream consumers.
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
### SaveGroups
|
||
|
|
```csharp
|
||
|
|
public class SaveGroups : SaveVariantBase
|
||
|
|
{
|
||
|
|
public bool CanCurrentUserCommitChannelCodes { get; set; } = true;
|
||
|
|
public IChannelSetting DefaultZeroMethod { get; set; }
|
||
|
|
public IChannelSetting DefaultZeroStart { get; set; }
|
||
|
|
public IChannelSetting DefaultZeroEnd { get; set; }
|
||
|
|
public IChannelSetting DefaultInitialOffset { get; set; }
|
||
|
|
public Dictionary<int?, int> OldGroupIdToNewGroupId { get; set; }
|
||
|
|
|
||
|
|
public SaveGroups(ImportObject importObject, IPersistCalculator persistCalculator,
|
||
|
|
IImportNotification importNotification, SaveHardware saveHardware,
|
||
|
|
Func<bool> isCancelled = null)
|
||
|
|
|
||
|
|
public override void Save()
|
||
|
|
}
|
||
|
|
```
|
||
|
|
Persists static groups. Requires `SaveHardware` instance for DAS ID remapping. Updates sensor IDs and fixes missing zero method parameters.
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
### SaveCustomChannels
|
||
|
|
```csharp
|
||
|
|
public class SaveCustomChannels : SaveVariantBase
|
||
|
|
{
|
||
|
|
public ISO13499FileDb IsoDb { get; set; }
|
||
|
|
public Dictionary<string, string> CustomChannelTextIdToOldChannelId { get; set; }
|
||
|
|
public Dictionary<string, TestObjectChannel> CustomChannelOldChannelIdToChannel { get; set; }
|
||
|
|
|
||
|
|
public SaveCustomChannels(ImportObject importObject, IPersistCalculator persistCalculator,
|
||
|
|
IImportNotification importNotification, Func<bool> isCancelled = null)
|
||
|
|
|
||
|
|
public override void Save()
|
||
|
|
}
|
||
|
|
```
|
||
|
|
Persists custom channels with complex ID remapping logic. Maintains mappings for level trigger updates in test setups.
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
### SaveTestSetup
|
||
|
|
```csharp
|
||
|
|
public class SaveTestSetup : SaveVariantBase
|
||
|
|
{
|
||
|
|
public User CurrentUser { get; set; }
|
||
|
|
public string TestSetupName { get; set; }
|
||
|
|
|
||
|
|
public SaveTestSetup(ImportObject importObject, IPersistCalculator persistCalculator,
|
||
|
|
IImportNotification importNotification, SaveCustomChannels saveCustomChannels,
|
||
|
|
SaveHardware saveHardware, SaveGroups saveGroups, Func<bool> isCancelled = null)
|
||
|
|
|
||
|
|
public override void Save()
|
||
|
|
}
|
||
|
|
```
|
||
|
|
Persists test setups. Requires `SaveCustomChannels`, `SaveHardware`, and `SaveGroups` for cross-entity ID resolution.
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
### SaveCheckoutTestSetup
|
||
|
|
```csharp
|
||
|
|
public class SaveCheckoutTestSetup : SaveVariantBase
|
||
|
|
{
|
||
|
|
public User CurrentUser { get; set; }
|
||
|
|
|
||
|
|
public SaveCheckoutTestSetup(ImportObject importObject, IPersistCalculator persistCalculator,
|
||
|
|
IImportNotification importNotification, SaveCustomChannels saveCustomChannels,
|
||
|
|
SaveHardware saveHardware, SaveGroups saveGroups,
|
||
|
|
Func<bool> isCancelled = null, string setupName = null)
|
||
|
|
|
||
|
|
public override void Save()
|
||
|
|
}
|
||
|
|
```
|
||
|
|
Persists checkout-mode test setups with different default configuration than `SaveTestSetup`.
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
### SaveUsers
|
||
|
|
```csharp
|
||
|
|
public class SaveUsers : SaveVariantBase
|
||
|
|
{
|
||
|
|
public IUIItems[] UIItems { get; set; }
|
||
|
|
public User CurrentUser { get; set; }
|
||
|
|
|
||
|
|
public SaveUsers(ImportObject importObject, IPersistCalculator persistCalculator,
|
||
|
|
IImportNotification importNotification, Func<bool> isCancelled = null)
|
||
|
|
|
||
|
|
public override void Save()
|
||
|
|
}
|
||
|
|
```
|
||
|
|
Persists users. Requires `CurrentUser.IsAdmin` to be true (asserted via `Trace.Assert`).
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
### SaveSensorModels
|
||
|
|
```csharp
|
||
|
|
public class SaveSensorModels : SaveVariantBase
|
||
|
|
{
|
||
|
|
public User CurrentUser { get; set; }
|
||
|
|
|
||
|
|
public SaveSensorModels(ImportObject importObject, IPersistCalculator persistCalculator,
|
||
|
|
IImportNotification importNotification, Func<bool> isCancelled = null)
|
||
|
|
|
||
|
|
public override void Save()
|
||
|
|
}
|
||
|
|
```
|
||
|
|
Persists sensor models via `SensorModelCollection.SensorModelList.Commit()`.
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
### SaveGlobalSettings
|
||
|
|
```csharp
|
||
|
|
public class SaveGlobalSettings : SaveVariantBase
|
||
|
|
{
|
||
|
|
public SaveGlobalSettings(ImportObject importObject, IPersistCalculator persistCalculator,
|
||
|
|
IImportNotification importNotification, Func<bool> isCancelled = null)
|
||
|
|
|
||
|
|
public override void Save()
|
||
|
|
}
|
||
|
|
```
|
||
|
|
Persists global settings via `SettingsDB.SetGlobalValue()`.
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
### SaveTestEngineerDetails
|
||
|
|
```csharp
|
||
|
|
public class SaveTestEngineerDetails : SaveVariantBase
|
||
|
|
{
|
||
|
|
public SaveTestEngineerDetails(ImportObject importObject, IPersistCalculator persistCalculator,
|
||
|
|
IImportNotification importNotification, Func<bool> isCancelled = null)
|
||
|
|
|
||
|
|
public override void Save()
|
||
|
|
}
|
||
|
|
```
|
||
|
|
Persists test engineer details via `TestEngineerDetailsList.TestEngineerList.AddTestEngineer()`.
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
### SaveLabDetails
|
||
|
|
```csharp
|
||
|
|
public class SaveLabDetails : SaveVariantBase
|
||
|
|
{
|
||
|
|
public SaveLabDetails(ImportObject importObject, IPersistCalculator persistCalculator,
|
||
|
|
IImportNotification importNotification, Func<bool> isCancelled = null)
|
||
|
|
|
||
|
|
public override void Save()
|
||
|
|
}
|
||
|
|
```
|
||
|
|
Persists laboratory details. Skips invalid/blank entries via `IsInvalidBlank()` check.
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
### SaveCustomerDetails
|
||
|
|
```csharp
|
||
|
|
public class SaveCustomerDetails : SaveVariantBase
|
||
|
|
{
|
||
|
|
public SaveCustomerDetails(ImportObject importObject, IPersistCalculator persistCalculator,
|
||
|
|
IImportNotification importNotification, Func<bool> isCancelled = null)
|
||
|
|
|
||
|
|
public override void Save()
|
||
|
|
}
|
||
|
|
```
|
||
|
|
Persists customer details. Skips invalid/blank entries via `IsInvalidBlank()` check.
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
### SaveGroupTemplates
|
||
|
|
```csharp
|
||
|
|
public class SaveGroupTemplates : SaveVariantBase
|
||
|
|
{
|
||
|
|
public SaveGroupTemplates(ImportObject importObject, IPersistCalculator persistCalculator,
|
||
|
|
IImportNotification importNotification, Func<bool> isCancelled = null)
|
||
|
|
|
||
|
|
public override void Save()
|
||
|
|
}
|
||
|
|
```
|
||
|
|
Iterates group templates and updates progress. **Note: Does not appear to persist any data to database.**
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
### SaveServer
|
||
|
|
```csharp
|
||
|
|
class SaveServer : SaveVariantBase
|
||
|
|
{
|
||
|
|
public SaveServer(ImportObject importObject, IPersistCalculator persistCalculator,
|
||
|
|
IImportNotification importNotification, Func<bool> isCancelled = null)
|
||
|
|
|
||
|
|
public override void Save() // Throws NotImplementedException
|
||
|
|
}
|
||
|
|
```
|
||
|
|
Stub implementation. **Not implemented.**
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
### SaveTestSetupHelper (Static Helper)
|
||
|
|
```csharp
|
||
|
|
public static class SaveTestSetupHelper
|
||
|
|
{
|
||
|
|
public static void AddHardwareFromEmbeddedGroups(TestTemplate t, SaveGroups saveGroups,
|
||
|
|
List<int> hardwareRemoved, List<int> hardwareIncluded)
|
||
|
|
|
||
|
|
public static void FixDasAff(Dictionary<string, DASHardware> hardwareLookup, TestTemplate t)
|
||
|
|
|
||
|
|
public static Dictionary<string, DASHardware> PopulateHarwareLookup()
|
||
|
|
|
||
|
|
public static void DeleteExistingTestSetups(IEnumerable<TestTemplate> testSetups, string userName)
|
||
|
|
|
||
|
|
public static void UpdateLevelTriggers(ref Dictionary<string, string> oldIdToNewIdLookup,
|
||
|
|
SaveCustomChannels saveCustomChannels, IEnumerable<TestTemplate> testSetups)
|
||
|
|
}
|
||
|
|
```
|
||
|
|
Shared utility methods for test setup persistence operations.
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 3. Invariants
|
||
|
|
|
||
|
|
1. **Progress Calculation**: `ProgressValue` is calculated as `_done / _total`. If `_total` is 0, this will result in division by zero (not guarded against).
|
||
|
|
|
||
|
|
2. **AddToTotal Validation**: `PersistCalculator.AddToTotal(double value)` throws `ArgumentOutOfRangeException` if `value < 0`. The exception message states "value should not be less or equal to zero" but the check is only for `< 0`, not `<= 0`.
|
||
|
|
|
||
|
|
3. **Cancellation Default**: If `isCancelled` parameter is null, `IsCancelled` defaults to `() => false`, meaning the operation will never be cancelled.
|
||
|
|
|
||
|
|
4. **SaveUsers Admin Requirement**: `SaveUsers.Save()` asserts `CurrentUser.IsAdmin` must be true via `Trace.Assert`. This is a debug-only assertion, not a runtime exception.
|
||
|
|
|
||
|
|
5. **SaveHardware ID Tracking**: `OldDASIdToNewDASId` only contains entries when `h.DASId != oldId` after commit. Unchanged IDs are not tracked.
|
||
|
|
|
||
|
|
6. **SaveGroups Dependency**: `SaveGroups` requires a `SaveHardware` instance in its constructor to access `OldDASIdToNewDASId` for channel DAS ID remapping.
|
||
|
|
|
||
|
|
7. **SaveTestSetup/SaveCheckoutTestSetup Dependencies**: Both require `SaveCustomChannels`, `SaveHardware`, and `SaveGroups` instances for cross-entity ID resolution.
|
||
|
|
|
||
|
|
8. **Hardware Sort Order**: `SaveHardware.Save()` calls `.Sort()` on the hardware list before processing, implying hardware must implement `IComparable`.
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 4. Dependencies
|
||
|
|
|
||
|
|
### External Dependencies (Inferred from Imports)
|
||
|
|
|
||
|
|
| Module | Dependencies |
|
||
|
|
|--------|--------------|
|
||
|
|
| `SaveHardware` | `DataPROWin7.DataModel.Classes.Hardware`, `DTS.Common.Interface.DASFactory.Diagnostics`, `DTS.Common.SharedResource.Strings` |
|
||
|
|
| `SaveGroups` | `DataPROWin7.DataModel.Classes.Hardware`, `DTS.Common.Classes.Groups.ChannelSettings`, `DTS.Common.Interface.Channels`, `DTS.Common.Interface.Groups.GroupList`, `DTS.Common.SharedResource.Strings`, `DTS.Common.Storage` |
|
||
|
|
| `SaveCustomChannels` | `DataPROWin7.DataModel`, `DTS.Common.ISO` |
|
||
|
|
| `SaveTestSetup`, `SaveCheckoutTestSetup` | `DataPROWin7.DataModel`, `DataPROWin7.DataModel.Classes.Hardware`, `DTS.SensorDB`, `DTS.Slice.Users` |
|
||
|
|
| `SaveUsers` | `DTS.Slice.Users` |
|
||
|
|
| `SaveSensorModels` | `DTS.SensorDB`, `DTS.Slice.Users` |
|
||
|
|
| `SaveGlobalSettings` | `DTS.Common.Settings` |
|
||
|
|
| `SaveTestEngineerDetails`, `SaveLabDetails`, `SaveCustomerDetails` | `DataPROWin7.DataModel`, `DTS.Common.Import.Enums` |
|
||
|
|
| `SaveVariantBase` | `DTS.Common.Import.Interfaces` |
|
||
|
|
|
||
|
|
### Internal Dependencies
|
||
|
|
|
||
|
|
- All save variants depend on `ImportObject`, `IPersistCalculator`, and `IImportNotification`
|
||
|
|
- `SaveTestSetup`, `SaveCheckoutTestSetup` depend on `SaveCustomChannels`, `SaveHardware`, `SaveGroups`
|
||
|
|
- `SaveGroups` depends on `SaveHardware`
|
||
|
|
- `SaveTestSetupHelper` depends on `SaveGroups`, `SaveCustomChannels`
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 5. Gotchas
|
||
|
|
|
||
|
|
1. **SaveServer Not Implemented**: `SaveServer.Save()` throws `NotImplementedException`. This class should not be used in production.
|
||
|
|
|
||
|
|
2. **SaveGroupTemplates No Persistence**: `SaveGroupTemplates.Save()` iterates through group templates and updates progress but does not appear to commit any data to the database.
|
||
|
|
|
||
|
|
3. **Copy-Paste Error in SaveCustomerDetails**: The status is set to `ImportExtraStatus.ReadingLabDetails` instead of a customer-specific status. This appears to be a copy-paste error from `SaveLabDetails`.
|
||
|
|
|
||
|
|
4. **Division by Zero Risk**: `PersistCalculator.ProgressValue` does not guard against `_total` being zero, which would cause division by zero.
|
||
|
|
|
||
|
|
5. **Debug-Only Admin Check**: `SaveUsers` uses `Trace.Assert` for admin validation, which only fires in debug builds. In release builds, a non-admin user could attempt the import without exception.
|
||
|
|
|
||
|
|
6. **Invalid Details Tracking**: `SaveLabDetails` and `SaveCustomerDetails` set local `invalidLabDetails`/`invalidCustomerDetails` flags when encountering invalid entries, but these flags are never used or reported.
|
||
|
|
|
||
|
|
7. **Hardware List Mutation**: `SaveHardware.Save()` calls `.ToList().Sort()` on `_importObject.Hardware()`, which may have side effects on the underlying collection depending on implementation.
|
||
|
|
|
||
|
|
8. **Missing Error Reporting**: `SaveTestSetup.Save()` and `SaveCheckoutTestSetup.Save()` check `if (_importObject.Errors().Any())` but the body is empty with only a comment `//report errors`.
|
||
|
|
|
||
|
|
9. **Typo in Method Name**: `SaveTestSetupHelper.PopulateHarwareLookup()` is misspelled (should be "Hardware").
|
||
|
|
|
||
|
|
10. **GC.Collect Commented Out**: In `SaveCustomChannels.Save()`, there is a commented-out `GC.Collect()` with a comment acknowledging it as a "critical code smell" (referencing bug #11287 for out-of-memory exceptions with large CSV files).
|