Files
DP44/enriched-partialglm/Common/DTS.Common.SettingsDB.md
2026-04-17 14:55:32 -04:00

8.8 KiB

source_files, generated_at, model, schema_version, sha256
source_files generated_at model schema_version sha256
Common/DTS.Common.SettingsDB/UserSetting.cs
Common/DTS.Common.SettingsDB/Setting.cs
Common/DTS.Common.SettingsDB/GlobalSetting.cs
Common/DTS.Common.SettingsDB/SettingsDB.cs
2026-04-16T11:31:14.800080+00:00 zai-org/GLM-5-FP8 1 0690ee9f2887691d

Documentation: DTS.Common.Settings

1. Purpose

This module provides a persistent settings management system that stores and retrieves application configuration values in a SQL database. It supports two categories of settings: global settings (application-wide, identified by the "SYSTEM" user) and user-specific settings (scoped to individual users). The SettingsDB class serves as the primary facade, implementing a thread-safe singleton pattern with in-memory caching to minimize database round-trips. Settings are serialized as strings in the database, with helper methods provided for type conversion to/from int, double, bool, and arrays.


2. Public Interface

Setting (Abstract Base Class)

The abstract base class for all setting types.

Properties:

  • string PropertyId — The string identifier for the setting.
  • PropertyTypes PropertyType — Either PropertyTypes.User (1) or PropertyTypes.Global (2).
  • string PropertyValue — The current value of the setting.
  • string UserId — The user identifier; "SYSTEM" for global settings.

Methods:

  • void SetValue(string value) — Updates the in-memory value and persists it to the database via StoreInDB().

Nested Types:

  • enum PropertyTypes — Values: User = 1, Global = 2.

GlobalSetting (Class, inherits Setting)

Represents an application-wide setting.

Constructors:

  • GlobalSetting(string id, string defaultPropertyValue) — Creates or retrieves a global setting with the given ID and default value.

Static Methods:

  • GlobalSetting ReadXML(System.Xml.XmlElement root) — Parses an XML element to construct a GlobalSetting. Expects child elements matching XMLFields.NAME and XMLFields.VALUE.
  • GlobalSetting[] GetAllGlobalSettings() — Retrieves all global settings from the database. Returns an empty array on failure.

Nested Types:

  • enum XMLFields — Values: NAME, VALUE. Used for XML parsing.
  • class NullDefaultValueException : NullReferenceException — Thrown when a setting doesn't exist and no default value is provided.

UserSetting (Class, inherits Setting)

Represents a user-specific setting.

Constructors:

  • UserSetting(string id, string defaultValue, string user) — Creates or retrieves a user-specific setting for the given user.

SettingsDB (Static Facade Class)

The primary interface for interacting with settings. Implements a thread-safe singleton with caching.

Static Methods:

Method Description
void RefreshSettings() Clears the in-memory settings cache.
string GetUserValue(string id, string defaultValue, string user) Retrieves a user-specific value; creates with default if not exists.
string GetGlobalValue(string id, string defaultValue, bool useCache = true) Retrieves a global value; creates with default if not exists. Optionally bypasses cache.
void GetAllGlobalValues() Loads all global settings into the cache.
double GetGlobalValueDouble(string id, double defaultValue) Retrieves a global value parsed as double.
int GetGlobalValueInt(string id, int defaultValue) Retrieves a global value parsed as int.
bool GetGlobalValueBool(string id, bool defaultValue, bool useCache = true) Retrieves a global value parsed as bool.
double[] GetGlobalValueDoubleArray(string id, double[] defaultValues) Retrieves an array of doubles stored as separate keys ({id}_x_Count, {id}_x_0, etc.).
int[] GetGlobalValueIntArray(string id, int[] defaultValues) Retrieves an array of ints stored as separate keys.
void SetUserValue(string id, string value, string user) Sets a user-specific value in the database.
void SetGlobalValue(string id, string value) Sets a global string value.
void SetGlobalValueDouble(string id, double value) Sets a global double value.
void SetGlobalValueInt(string id, int value) Sets a global int value.
void SetGlobalValueBoolean(string id, bool value) Sets a global bool value.
void SetGlobalValueDoubleArray(string id, double[] values) Stores a double array as multiple keys.
void SetGlobalValueIntArray(string id, int[] values) Stores an int array as multiple keys.

3. Invariants

  1. Thread Safety: All public methods in SettingsDB acquire a lock on LOCK_OBJECT before accessing _settingsLookup. The singleton instance is lazily initialized under lock.

  2. Key Uniqueness: User-specific settings use a composite key format {id}_{user} in the cache; global settings use {id} directly.

  3. Global Settings Identity: All GlobalSetting instances use UserId = "SYSTEM" (defined as a private constant).

  4. Database Synchronization: Calling SetValue() on any Setting instance immediately persists the value to the database via StoreInDB().

  5. Auto-Creation on Missing: When a setting is retrieved but doesn't exist in the database, it is automatically created with the provided default value and persisted.

  6. Array Storage Convention: Arrays are stored as multiple database records:

    • {id}_x_Count — The number of elements.
    • {id}_x_{i} — The value at index i.
  7. Culture Invariance: All numeric-to-string conversions use CultureInfo.InvariantCulture.


4. Dependencies

This Module Depends On:

  • System.Data — For CommandType, SqlParameter, SqlDbType, ParameterDirection.
  • System.Data.SqlClient — For SqlConnection/SqlCommand operations (implied via SqlParameter).
  • DTS.Common.Storage — Provides:
    • DbOperations.GetSQLCommand(bool)
    • DbOperations.Connection.QueryDataSet(SqlCommand)
    • DbOperationsEnum.StoredProcedure (enum with sp_SettingsGet, sp_SettingsUpdateInsert)
    • DbOperations.Settings.UserFields.PropertyValue (enum)
  • DTS.Common.Utilities.Logging — Provides APILogger.LogException(Exception) and APILogger.Log(string, Exception).

Database Dependencies:

  • Stored Procedure: sp_SettingsGet — Retrieves settings by @UserId and @PropertyId.
  • Stored Procedure: sp_SettingsUpdateInsert — Inserts or updates a setting. Parameters: @PropertyId, @PropertyType, @PropertyValue, @UserId, @new_id (output), @errorNumber (output), @errorMessage (output).

5. Gotchas

  1. Silent Exception Swallowing in UserSetting.GetPropertyValue: All exceptions are caught and silently ignored; the method falls back to the default value without logging. This can mask database connectivity issues or data corruption.

  2. Unused Error Output Parameters: In Setting.StoreInDB(), the stored procedure returns @errorNumber and @errorMessage, but the code checks if errorNumber != 0 and then does nothing (empty block). Errors from the database are silently ignored.

  3. Max Length Constraint Not Enforced in Code: The PropertyValue property documentation states "there is a max length" but no validation occurs before database insertion. The stored procedure parameters specify length 255 for string values.

  4. Redundant cmd.Connection.Dispose(): All database methods call cmd.Connection.Dispose() inside a finally block, but the cmd is already inside a using statement. This is redundant and potentially confusing.

  5. Backward Compatibility Hack for ImportCreateDynamicGroups: SettingsDB contains special-case logic for migrating from CSV_IMPORT_CREATE_DYNAMIC_GROUPS to IMPORT_CREATE_DYNAMIC_GROUPS. When setting the new key, it also sets the old key for pre-Version 93 client compatibility. This is documented in comments referencing issue 36831.

  6. GetGlobalValueBool Parsing Logic Error: The method contains return !bool.TryParse(sValue, out b) ? b : b; — both branches return b, making the conditional meaningless. It should likely return defaultValue on parse failure.

  7. NullDefaultValueException Only Thrown by GlobalSetting: UserSetting.GetPropertyValue does not throw this exception; it silently falls back to the default. Only GlobalSetting.GetPropertyValue throws NullDefaultValueException when the setting doesn't exist and defaultValue is null.

  8. TODO Comments Indicate Incomplete Work:

    • UserSetting.GetPropertyValue line 42: //TODO: handle exception properly
    • GlobalSetting.ProcessXMLElement line 68: // TODO: handle exception properly
  9. Cache Bypass Only Affects Retrieval: GetGlobalValue(id, defaultValue, useCache: false) bypasses the cache when reading, but SetGlobalValue always updates the cache. This can lead to stale cache entries if another process modifies the database directly.