Files
DP44/enriched-partialglm/Common/DTS.Common.Import/Persist.md

315 lines
14 KiB
Markdown
Raw Normal View History

2026-04-17 14:55:32 -04:00
---
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-16T11:46:11.806575+00:00"
model: "zai-org/GLM-5-FP8"
schema_version: 1
sha256: "695fcda61b684601"
---
# DTS.Common.Import.Persist Module Documentation
## 1. Purpose
This module implements the persistence layer for an import system, responsible for saving various imported data entities (hardware, users, test setups, groups, sensors, etc.) to a database. It follows the Strategy pattern where each `SaveVariantBase` subclass handles a specific entity type, providing a unified interface (`IPersistImport`) for the import pipeline while supporting progress tracking, cancellation, and error reporting.
---
## 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 reporting, cancellation checking, and access to the import data object.
### IPersistCalculator / PersistCalculator
```csharp
public interface IPersistCalculator
{
void AddDone();
void AddDone(double value);
double ProgressValue { get; }
void AddToTotal(double value);
}
public class PersistCalculator : IPersistCalculator
{
public double ProgressValue { get; } // Returns _done / _total
public void AddDone();
public void AddDone(double value);
public void AddToTotal(double value); // Throws ArgumentOutOfRangeException if value < 0
}
```
Tracks progress as a ratio of completed work (`_done`) to total work (`_total`).
### SaveServer
```csharp
public class SaveServer : SaveVariantBase
{
public SaveServer(ImportObject importObject, IPersistCalculator persistCalculator,
IImportNotification importNotification, Func<bool> isCancelled = null)
public override void Save(); // Throws NotImplementedException
}
```
Stub implementation — currently unimplemented.
### SaveGroupTemplates
```csharp
public class SaveGroupTemplates : SaveVariantBase
{
public SaveGroupTemplates(ImportObject importObject, IPersistCalculator persistCalculator,
IImportNotification importNotification, Func<bool> isCancelled = null)
public override void Save(); // Iterates _importObject.GroupTemplates(), updates progress
}
```
Iterates group templates without persisting them (appears to be a placeholder that only updates progress).
### SaveGlobalSettings
```csharp
public class SaveGlobalSettings : SaveVariantBase
{
public override void Save(); // Calls SettingsDB.SetGlobalValue(g.Key, g.Value) for each setting
}
```
Persists global settings via `SettingsDB.SetGlobalValue()`.
### SaveSensorModels
```csharp
public class SaveSensorModels : SaveVariantBase
{
public User CurrentUser { get; set; }
public override void Save(); // Commits sensor models via SensorModelCollection.SensorModelList.Commit()
}
```
Persists sensor models. Requires `CurrentUser` to be set for the commit operation.
### SaveTestEngineerDetails
```csharp
public class SaveTestEngineerDetails : SaveVariantBase
{
public override void Save(); // Adds test engineers via TestEngineerDetailsList.TestEngineerList.AddTestEngineer()
}
```
Persists test engineer details. Sets status to `ImportExtraStatus.ReadingEngineerDetails`.
### SaveLabDetails
```csharp
public class SaveLabDetails : SaveVariantBase
{
public override void Save(); // Adds labs via LabratoryDetailsList.AddLab()
}
```
Persists lab details. Skips invalid/blank entries (calls `l.IsInvalidBlank()`). Sets status to `ImportExtraStatus.ReadingLabDetails`.
### SaveUsers
```csharp
public class SaveUsers : SaveVariantBase
{
public IUIItems[] UIItems { get; set; }
public User CurrentUser { get; set; }
public override void Save(); // Commits users via UserCollection.UsersList.Commit()
}
```
Persists users. **Asserts** that `CurrentUser.IsAdmin` is true (will fail in debug builds if non-admin attempts import). Sets status to `ImportExtraStatus.ReadingUsers`.
### SaveCustomerDetails
```csharp
public class SaveCustomerDetails : SaveVariantBase
{
public override void Save(); // Adds customers via CustomerDetailsList.AddCustomer()
}
```
Persists customer details. Skips invalid/blank entries. Note: Sets status to `ImportExtraStatus.ReadingLabDetails` (appears to be a copy-paste error).
### SaveHardware
```csharp
public class SaveHardware : SaveVariantBase
{
public Dictionary<int, int> OldDASIdToNewDASId { get; set; } = new Dictionary<int, int>();
public Dictionary<int, List<IISOHardware>> TestIdToHardware { get; set; } = new Dictionary<int, List<IISOHardware>>();
public override void Save(); // Commits hardware via DASHardwareList.GetList().Commit()
}
```
Persists hardware configurations. Tracks DAS ID remapping (`OldDASIdToNewDASId`) and hardware-to-test relationships (`TestIdToHardware`). Sorts hardware before processing. Progress includes both hardware items and their channels.
### 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; } = new Dictionary<int?, int>();
public SaveGroups(ImportObject importObject, IPersistCalculator persistCalculator,
IImportNotification importNotification, SaveHardware saveHardware, Func<bool> isCancelled = null)
public override void Save();
}
```
Persists static groups. Requires `SaveHardware` dependency for DAS ID remapping. Fixes missing zero method parameters and initial offsets. Maps old group IDs to new IDs. Reports warnings for groups with channels assigned to unknown DAS.
### SaveCustomChannels
```csharp
public class SaveCustomChannels : SaveVariantBase
{
public ISO13499FileDb IsoDb { get; set; }
public Dictionary<string, string> CustomChannelTextIdToOldChannelId { get; set; } = new Dictionary<string, string>();
public Dictionary<string, TestObjectChannel> CustomChannelOldChannelIdToChannel { get; set; } = new Dictionary<string, TestObjectChannel>();
public override void Save();
}
```
Persists custom channels via `CustomChannelList.List.Commit()`. Handles ID remapping for existing channels. Updates group templates and groups that reference custom channels. Calls `CustomChannelList.List.UpdateAll()` at the end.
### 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 via `TestTemplateList.TestTemplatesList.Commit()`. Requires dependencies on `SaveCustomChannels`, `SaveHardware`, and `SaveGroups`. Handles special case for `ImportFileFormat.SingleTestSetup` with custom naming. Deletes existing test setups before import. Updates hardware `TestId` references after commit.
### 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 test setups with specific configuration (checkout mode enabled, missing sensors allowed, etc.). Creates new groups from `ChannelsForGroup` configuration.
### SaveTestSetupHelper (Static Class)
```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);
}
```
Helper methods extracted for reuse between `SaveTestSetup` and `SaveCheckoutTestSetup`.
---
## 3. Invariants
1. **Cancellation Check Pattern**: All `Save()` implementations check `IsCancelled()` at the start of each iteration loop and return immediately if true.
2. **Progress Reporting Pattern**: After each item is processed, implementations call `_persistCalculator.AddDone()` followed by `_importNotification.SetProgress(_persistCalculator.ProgressValue)`.
3. **Constructor Signature**: All `SaveVariantBase` subclasses accept the same base parameters: `ImportObject`, `IPersistCalculator`, `IImportNotification`, and optional `Func<bool> isCancelled`.
4. **Null Cancellation Handler**: If `isCancelled` is null, `SaveVariantBase` assigns a lambda returning `false`.
5. **ProgressValue Calculation**: `ProgressValue` is calculated as `_done / _total`. Division by zero is possible if `AddToTotal()` is never called (undefined behavior in source).
6. **AddToTotal Validation**: `PersistCalculator.AddToTotal()` throws `ArgumentOutOfRangeException` if `value < 0`.
7. **Hardware ID Mapping**: `SaveHardware` always populates `OldDASIdToNewDASId` when DAS IDs change during commit.
8. **Group ID Mapping**: `SaveGroups` always populates `OldGroupIdToNewGroupId` for non-embedded static groups.
---
## 4. Dependencies
### This module depends on:
- **DTS.Common.Import.Interfaces** - `IPersistImport` interface (inferred)
- **DTS.Common.Settings** - `SettingsDB` for global settings persistence
- **DTS.SensorDB** - `SensorModelCollection`, `SensorsCollection` for sensor data
- **DTS.Slice.Users** - `User`, `UserCollection`, `IUIItems` for user management
- **DataPROWin7.DataModel** - Core data models (`TestTemplate`, `DASHardware`, `CustomerDetails`, `LabratoryDetails`, `TestEngineerDetails`, `CustomChannel`, etc.)
- **DTS.Common.Import.Enums** - `ImportStatus`, `ImportExtraStatus`, `PossibleStatus`, `ImportFileFormat`, `ImportSeverityError`
- **DTS.Common.Interface.Channels** - Channel interfaces
- **DTS.Common.Interface.Groups.GroupList** - `IGroup`, `IGroupChannel`, `GroupHelper`
- **DTS.Common.SharedResource.Strings** - `StringResources` for localized error messages
- **DTS.Common.Storage** - `DbOperations` for database queries
- **DTS.Common.ISO** - `ISO13499FileDb`, `IsoCodeStatics`, `MMEPossibleChannels`
- **DTS.Common.Classes.Groups.ChannelSettings** - `ChannelSettingBase`, `IChannelSetting`
- **DTS.Common.Interface.DASFactory.Diagnostics** - Diagnostics interfaces
- **DTS.Common.Enums** - `SupportedExportFormatBitFlags`
### What depends on this module:
- Cannot be determined from source alone (no consumers shown).
---
## 5. Gotchas
1. **SaveServer is unimplemented**: Calling `Save()` on `SaveServer` throws `NotImplementedException`.
2. **SaveCustomerDetails status typo**: Sets `ImportExtraStatus.ReadingLabDetails` instead of a customer-specific status (likely copy-paste error from `SaveLabDetails`).
3. **SaveUsers admin assertion**: Uses `Trace.Assert` to verify admin status — this only triggers in debug builds; production builds will silently proceed with potentially unauthorized operations.
4. **SaveGroupTemplates does nothing**: Iterates group templates but performs no persistence — only updates progress.
5. **Division by zero risk**: `PersistCalculator.ProgressValue` returns `_done / _total` without checking if `_total` is zero.
6. **SaveHardware sorts in-place**: Calls `_importObject.Hardware().ToList().Sort()` but then iterates the original `_importObject.Hardware()` — unclear if this has any effect since `ToList()` creates a copy.
7. **SaveCustomChannels memory concern**: Contains commented-out `GC.Collect()` with a code smell note referencing issue #11287 (out of memory exceptions on large CSV imports).
8. **Interdependent save order**: `SaveGroups` requires `SaveHardware` to be executed first (needs `OldDASIdToNewDASId`). `SaveTestSetup` requires `SaveCustomChannels`, `SaveHardware`, and `SaveGroups`. Order of execution matters.
9. **SaveCheckoutTestSetup clears groups**: Explicitly clears `t.Groups` and `t.ChannelsForGroup` before repopulating — this modifies the import object state.
10. **SaveTestSetup and SaveCheckoutTestSetup delete existing setups**: Both call `DeleteExistingTestSetups()` which removes existing test setups by name before importing.