--- 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-16T02:08:08.051368+00:00" model: "Qwen/Qwen3-Coder-Next-FP8" schema_version: 1 sha256: "695fcda61b684601" --- # Documentation: `DTS.Common.Import.Persist` Module ## 1. Purpose This module provides a family of concrete implementations for persisting various types of imported data during a data import workflow. Each class (`Save*`) corresponds to a distinct category of data (e.g., hardware, groups, test setups, users, custom channels) and encapsulates the logic required to commit that data to the target database or system. All implementations inherit from the abstract base class `SaveVariantBase`, which provides shared infrastructure for progress tracking, cancellation support, and dependency injection of core services (`IPersistCalculator`, `IImportNotification`). The module serves as the persistence layer of the import pipeline, transforming in-memory `ImportObject` data into persistent system state. ## 2. Public Interface All classes listed below are `public` (except `SaveServer`, which is `internal`) and inherit from `SaveVariantBase`. Each implements the `Save()` method. ### `SaveVariantBase` (abstract base class) - **Namespace**: `DTS.Common.Import.Persist` - **Signature**: `public abstract class SaveVariantBase : IPersistImport` - **Constructor**: ```csharp protected SaveVariantBase(ImportObject importObject, IPersistCalculator persistCalculator, IImportNotification importNotification, Func isCancelled = null) ``` - **Properties**: - `protected ImportObject _importObject` - `protected readonly IPersistCalculator _persistCalculator` - `protected readonly IImportNotification _importNotification` - `protected readonly Func IsCancelled` - **Methods**: - `public abstract void Save()` ### `SaveServer` (internal) - **Namespace**: `DTS.Common.Import.Persist` - **Signature**: `class SaveServer : SaveVariantBase` - **Constructor**: ```csharp public SaveServer(ImportObject importObject, IPersistCalculator persistCalculator, IImportNotification importNotification, Func isCancelled = null) ``` - **Methods**: - `public override void Save()` → **Throws `NotImplementedException`**. This class is a placeholder and not functional. ### `SaveGroupTemplates` - **Namespace**: `DTS.Common.Import.Persist` - **Signature**: `public class SaveGroupTemplates : SaveVariantBase` - **Constructor**: ```csharp public SaveGroupTemplates(ImportObject importObject, IPersistCalculator persistCalculator, IImportNotification importNotification, Func isCancelled = null) ``` - **Methods**: - `public override void Save()` Iterates over `_importObject.GroupTemplates()`. For each template: - Checks cancellation (`IsCancelled()`), returns early if true. - Calls `_persistCalculator.AddDone()` (increments by 1). - Calls `_importNotification.SetProgress(_persistCalculator.ProgressValue)`. **Note**: Does *not* actually commit group templates to storage; only updates progress. ### `SaveGlobalSettings` - **Namespace**: `DTS.Common.Import.Persist` - **Signature**: `public class SaveGlobalSettings : SaveVariantBase` - **Constructor**: ```csharp public SaveGlobalSettings(ImportObject importObject, IPersistCalculator persistCalculator, IImportNotification importNotification, Func isCancelled = null) ``` - **Methods**: - `public override void Save()` Iterates over `_importObject.GlobalSettings()`. For each setting `g`: - Checks cancellation, returns early if true. - Calls `SettingsDB.SetGlobalValue(g.Key, g.Value)`. - Calls `_persistCalculator.AddDone()` (increments by 1). - Calls `_importNotification.SetProgress(...)`. ### `SaveSensorModels` - **Namespace**: `DTS.Common.Import.Persist` - **Signature**: `public class SaveSensorModels : SaveVariantBase` - **Properties**: - `public User CurrentUser { get; set; }` - **Constructor**: ```csharp public SaveSensorModels(ImportObject importObject, IPersistCalculator persistCalculator, IImportNotification importNotification, Func isCancelled = null) ``` - **Methods**: - `public override void Save()` Iterates over `_importObject.SensorModels()`. For each model `st`: - Checks cancellation, returns early if true. - Calls `SensorModelCollection.SensorModelList.Commit(st, CurrentUser.UserName)`. - Calls `_persistCalculator.AddDone()` (increments by 1). - Calls `_importNotification.SetProgress(...)`. ### `SaveTestEngineerDetails` - **Namespace**: `DTS.Common.Import.Persist` - **Signature**: `public class SaveTestEngineerDetails : SaveVariantBase` - **Constructor**: ```csharp public SaveTestEngineerDetails(ImportObject importObject, IPersistCalculator persistCalculator, IImportNotification importNotification, Func isCancelled = null) ``` - **Methods**: - `public override void Save()` - First, calls `_importNotification.SetStatus.Invoke(...)` with `ExtraStatus = ImportExtraStatus.ReadingEngineerDetails`. - Iterates over `_importObject.TestEngineerDetails()`. For each detail `t`: - Checks cancellation, returns early if true. - Calls `TestEngineerDetailsList.TestEngineerList.AddTestEngineer(new TestEngineerDetails(t))`. - Calls `_persistCalculator.AddDone()` (increments by 1). - Calls `_importNotification.SetProgress(...)`. ### `SaveLabDetails` - **Namespace**: `DTS.Common.Import.Persist` - **Signature**: `public class SaveLabDetails : SaveVariantBase` - **Constructor**: ```csharp public SaveLabDetails(ImportObject importObject, IPersistCalculator persistCalculator, IImportNotification importNotification, Func isCancelled = null) ``` - **Methods**: - `public override void Save()` - First, calls `_importNotification.SetStatus.Invoke(...)` with `ExtraStatus = ImportExtraStatus.ReadingLabDetails`. - Declares `bool invalidLabDetails = false;` (but does *not* use it further). - Iterates over `_importObject.LabDetails()`. For each detail `l`: - Checks cancellation, returns early if true. - If `l.IsInvalidBlank()` is true, sets `invalidLabDetails = true`. - Otherwise, calls `LabratoryDetailsList.AddLab(new LabratoryDetails(l))`. - Calls `_persistCalculator.AddDone()` (increments by 1). - Calls `_importNotification.SetProgress(...)`. ### `SaveCustomerDetails` - **Namespace**: `DTS.Common.Import.Persist` - **Signature**: `public class SaveCustomerDetails : SaveVariantBase` - **Properties**: - `bool invalidCustomerDetails = false;` (instance field, not used beyond assignment) - **Constructor**: ```csharp public SaveCustomerDetails(ImportObject importObject, IPersistCalculator persistCalculator, IImportNotification importNotification, Func isCancelled = null) ``` - **Methods**: - `public override void Save()` - First, calls `_importNotification.SetStatus.Invoke(...)` with `ExtraStatus = ImportExtraStatus.ReadingLabDetails` *(note: likely a copy-paste error; should be `ReadingCustomerDetails`)*. - Iterates over `_importObject.CustomerDetails()`. For each detail `c`: - Checks cancellation, returns early if true. - If `c.IsInvalidBlank()` is true, sets `invalidCustomerDetails = true`. - Otherwise, calls `CustomerDetailsList.AddCustomer(new CustomerDetails(c))`. - Calls `_persistCalculator.AddDone()` (increments by 1). - Calls `_importNotification.SetProgress(...)`. ### `SaveUsers` - **Namespace**: `DTS.Common.Import.Persist` - **Signature**: `public class SaveUsers : SaveVariantBase` - **Properties**: - `public IUIItems[] UIItems { get; set; }` - `public User CurrentUser { get; set; }` - **Constructor**: ```csharp public SaveUsers(ImportObject importObject, IPersistCalculator persistCalculator, IImportNotification importNotification, Func isCancelled = null) ``` - **Methods**: - `public override void Save()` - First, calls `_importNotification.SetStatus.Invoke(...)` with `ExtraStatus = ImportExtraStatus.ReadingUsers`. - Iterates over `_importObject.Users()`. For each `user`: - Checks cancellation, returns early if true. - Asserts `CurrentUser.IsAdmin` via `System.Diagnostics.Trace.Assert(...)` (throws in debug if false). - Calls `UserCollection.UsersList.Commit(user, CurrentUser.UserName, UIItems)`. - Calls `_persistCalculator.AddDone()` (increments by 1). - Calls `_importNotification.SetProgress(...)`. ### `SaveHardware` - **Namespace**: `DTS.Common.Import.Persist` - **Signature**: `public class SaveHardware : SaveVariantBase` - **Properties**: - `public Dictionary OldDASIdToNewDASId { get; set; }` - `public Dictionary> TestIdToHardware { get; set; }` - **Constructor**: ```csharp public SaveHardware(ImportObject importObject, IPersistCalculator persistCalculator, IImportNotification importNotification, Func isCancelled = null) ``` - **Methods**: - `public override void Save()` - First, calls `_importNotification.SetStatus.Invoke(...)` with `ExtraStatus = ImportExtraStatus.ReadingHardware`. - Calls `_importObject.Hardware().ToList().Sort()` (sorts hardware list in-place). - Iterates over `_importObject.Hardware()`. For each hardware `h`: - Checks cancellation, returns early if true. - Stores `oldId = h.DASId`. - Calls `DASHardwareList.GetList().Commit(h, false, true)`. - If `h.DASId != oldId`, adds mapping `OldDASIdToNewDASId[oldId] = h.DASId`. - Gets `iso = h.GetHardware()`. If `iso.TestId != null`, adds `iso` to `TestIdToHardware[(int)iso.TestId]`. - Calls `_persistCalculator.AddDone()` (increments by 1). - Calls `_persistCalculator.AddDone(h.Channels?.Length ?? 0)` (adds number of channels). - Calls `_importNotification.SetProgress(...)`. ### `SaveGroups` - **Namespace**: `DTS.Common.Import.Persist` - **Signature**: `public class SaveGroups : SaveVariantBase` - **Properties**: - `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 OldGroupIdToNewGroupId { get; set; }` - `private readonly SaveHardware _saveHardware` - **Constructor**: ```csharp public SaveGroups(ImportObject importObject, IPersistCalculator persistCalculator, IImportNotification importNotification, SaveHardware saveHardware, Func isCancelled = null) ``` - **Methods**: - `public override void Save()` - First, calls `_importNotification.SetStatus.Invoke(...)` with `ExtraStatus = ImportExtraStatus.ReadingGroups`. - Builds `idToDASId` lookup from `DASHardwareList.GetAllHardware()`. - Retrieves channel defaults from `DbOperations.GetChannelSettingDefaults()` and assigns to `Default*` properties. - Iterates over `_importObject.StaticGroups()`. For each group `g`: - Checks cancellation, returns early if true. - If `!g.Embedded`: - For each channel `ch` in `g.GroupChannelList`: - Updates `ch.SensorId` using `_importObject.OldSensorDatabaseIdsToNew()`. - Updates `ch.DASId` using `_saveHardware.OldDASIdToNewDASId`; if missing, sets `ch.DASId = -1` and tracks group name in `missingDASGroupList`. - Calls `SaveSensor.FixMissingZeroMethodParameter(...)` and `SaveSensor.FixMissingInitialOffset(...)` (methods not defined in source). - Calls `SetGroupId(g)` (static helper) to resolve group ID from DB. - Calls `FixGroupHardware(g, idToDASId)` (static helper) to resolve hardware IDs. - Calls `g.Save(g.GroupChannelList.ToArray(), CanCurrentUserCommitChannelCodes)`. - Maps `OldGroupIdToNewGroupId[normalizedStaticGroupId] = g.Id`. - Calls `_persistCalculator.AddDone()` (increments by 1). - Calls `_importNotification.SetProgress(...)`. - If `missingDASGroupList.Any()`, reports a warning via `_importObject.AddError(...)`. ### `SaveCustomChannels` - **Namespace**: `DTS.Common.Import.Persist` - **Signature**: `public class SaveCustomChannels : SaveVariantBase` - **Properties**: - `public ISO13499FileDb IsoDb { get; set; }` - `public Dictionary CustomChannelTextIdToOldChannelId { get; set; }` - `public Dictionary CustomChannelOldChannelIdToChannel { get; set; }` - **Constructor**: ```csharp public SaveCustomChannels(ImportObject importObject, IPersistCalculator persistCalculator, IImportNotification importNotification, Func isCancelled = null) ``` - **Methods**: - `public override void Save()` - Early return if `_importObject.CustomChannels()` is null or empty. - Iterates over custom channels in reverse order. For each `cc`: - Checks cancellation, returns early if true. - Stores `oldid = cc.Id`. - Tries to find existing channel by ISO code (`CustomChannelList.List.GetChannelByISOCode(...)`). If found, uses its ID; otherwise, clears `cc.Id` and inserts. - Commits `new CustomChannel(cc)`. - For each group template in `_importObject.GroupTemplates()`: - If channel matches, updates its ID to `newid`. - Updates group templates and associated groups, preserving sensor/hardware IDs. - Populates `CustomChannelTextIdToOldChannelId` and `CustomChannelOldChannelIdToChannel` for later remapping. - Calls `_persistCalculator.AddDone()` (increments by 1). - Calls `_importNotification.SetProgress(...)`. - **Commented-out GC.Collect** indicates memory pressure concerns. - Calls `CustomChannelList.List.UpdateAll()`. ### `SaveTestSetup` - **Namespace**: `DTS.Common.Import.Persist` - **Signature**: `public class SaveTestSetup : SaveVariantBase` - **Properties**: - `private readonly SaveCustomChannels _saveCustomChannels` - `private readonly SaveHardware _saveHardware` - `private readonly SaveGroups _saveGroups` - `public User CurrentUser { get; set; }` - `public string TestSetupName { get; set; }` - **Constructor**: ```csharp public SaveTestSetup(ImportObject importObject, IPersistCalculator persistCalculator, IImportNotification importNotification, SaveCustomChannels saveCustomChannels, SaveHardware saveHardware, SaveGroups saveGroups, Func isCancelled = null) ``` - **Methods**: - `private void ConfigureDefaultRunTestTestSetup(TestTemplate testSetup)` Sets many boolean/numeric properties (e.g., `DoROIDownload = true`, `ExportFormats = rdfadc`, etc.) for run-test mode. - `public override void Save()` - If `ImportFileFormat == SingleTestSetup` and `TestSetupName` is set, overrides `Name`, `TestId`, and calls `ConfigureDefaultRunTestTestSetup(...)`. - Calls `SaveTestSetupHelper.UpdateLevelTriggers(...)` to remap level trigger channel IDs. - Calls `SaveTestSetupHelper.DeleteExistingTestSetups(...)` to delete existing test setups. - Calls `SaveTestSetupHelper.PopulateHarwareLookup()` to build `hardwareLookup`. - Iterates over `_importObject.TestSetups()`. For each `t`: - Calls `SaveTestSetupHelper.FixDasAff(...)` to fix DAS AAF rates. - Stores `idPriorToCommit = t.Id`, then sets `t.Id = 0`. - For each channel in `t.ChannelsForGroup`: - Updates `SensorId` and `DASId` using mappings from `_importObject` and `_saveHardware`. - Calls `SaveSensor.FixMissingZeroMethodParameter(...)` and `SaveSensor.FixMissingInitialOffset(...)`. - Updates `hardwareIncluded`/`hardwareRemoved` lists using `OldDASIdToNewDASId`. - Calls `SaveTestSetupHelper.AddHardwareFromEmbeddedGroups(...)`. - Calls `t.ReplaceCalculatedChannel(oldIdToNewIdLookup)`. - Checks cancellation, returns early if true. - Ensures `t.TestSetupUniqueId` is set (generates GUID if null). - Commits `t` via `TestTemplateList.TestTemplatesList.Commit(t, false)`. - If `idPriorToCommit > 0`, updates `TestId` on associated hardware in `_saveHardware.TestIdToHardware`. - Calls `_persistCalculator.AddDone()` (increments by 1). - Calls `_importNotification.SetProgress(...)`. - Clears `oldIdToNewIdLookup`. - Sets status to `ImportExtraStatus.None`/`PossibleStatus.Working`. ### `SaveCheckoutTestSetup` - **Namespace**: `DTS.Common.Import.Persist` - **Signature**: `public class SaveCheckoutTestSetup : SaveVariantBase` - **Properties**: - `private readonly SaveCustomChannels _saveCustomChannels` - `private readonly SaveHardware _saveHardware` - `private readonly SaveGroups _saveGroups` - `private readonly string _setupName` - `public User CurrentUser { get; set; }` - **Constructor**: ```csharp public SaveCheckoutTestSetup(ImportObject importObject, IPersistCalculator persistCalculator, IImportNotification importNotification, SaveCustomChannels saveCustomChannels, SaveHardware saveHardware, SaveGroups saveGroups, Func isCancelled = null, string setupName = null) ``` - **Methods**: - `private void ConfigureCheckoutTestSetup(TestTemplate TestSetupCheckout)` Sets many boolean properties for checkout mode (e.g., `CheckoutMode = true`, `AllowMissingSensors = true`, `ExportFormats = none`, etc.). -