Files
DP44/docs/ai/Common/DTS.Common.Import/Persist.md
2026-04-17 14:55:32 -04:00

14 KiB

source_files, generated_at, model, schema_version, sha256
source_files generated_at model schema_version sha256
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
2026-04-17T15:28:30.641712+00:00 zai-org/GLM-5-FP8 1 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)

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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)

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).