--- source_files: - DataPRO/Modules/DatabaseImporter/DatabaseImport/SettingsDB/GlobalSetting.cs - DataPRO/Modules/DatabaseImporter/DatabaseImport/SettingsDB/SettingsDB.cs - DataPRO/Modules/DatabaseImporter/DatabaseImport/SettingsDB/Setting.cs generated_at: "2026-04-16T04:30:58.292022+00:00" model: "Qwen/Qwen3-Coder-Next-FP8" schema_version: 1 sha256: "f40d6df6287d52df" --- # SettingsDB ## Documentation: Global Settings Module (`DatabaseImport`) --- ### 1. Purpose This module provides a centralized, thread-safe mechanism for managing **application-wide (global) settings** stored in a SQL Server database. It abstracts the persistence logic for global configuration properties, ensuring that each setting is lazily loaded from the database on first access, falls back to a provided default value if missing, and caches the setting instance in memory for subsequent lookups. It is part of the `DatabaseImporter` module and serves as the canonical source for global configuration values used during database import operations. --- ### 2. Public Interface #### `SettingsDB` (Static Class) - **`public static string GetGlobalValue(string id, string defaultValue)`** Retrieves the global setting value for `id`. If the setting does not exist in the cache or database, it is created with `defaultValue`, stored in the DB, and returned. Thread-safe via singleton + lock. - **`public static bool GetGlobalValueBool(string id, bool defaultValue)`** Retrieves the global setting as a `bool`. Converts the stored string value using `bool.TryParse`; if parsing fails, returns `defaultValue`. Thread-safe. - **`public static void SetGlobalValue(string id, string value)`** Sets the global setting `id` to `value`. Updates the in-memory cache and persists to the database via `StoreInDB()`. Thread-safe. - **`public static void SetGlobalValueBoolean(string id, bool value)`** Sets the global setting `id` to the string representation of `value` (using `InvariantCulture`). Updates cache and persists. Thread-safe. #### `GlobalSetting` (Concrete Class, inherits `Setting`) - **`public GlobalSetting(string id, string defaultPropertyValue)`** Constructor. Initializes a `GlobalSetting` with `PropertyType = Global`, `UserId = "SYSTEM"`, and triggers `GetPropertyValue(defaultPropertyValue)`. #### `Setting` (Abstract Base Class) - **`public string PropertyId { get; }`** Read-only identifier of the setting (e.g., `"ImportBatchSize"`). - **`public string PropertyValue { get; }`** Current value of the setting (as `string`). *Note: No length validation is enforced at this layer.* - **`public string UserId { get; }`** User context for the setting. For `GlobalSetting`, this is always `"SYSTEM"`. - **`public void SetValue(string value)`** Updates `_propertyValue` and persists the change via `StoreInDB()`. - **`protected abstract void GetPropertyValue(string defaultValue)`** Implemented by subclasses to fetch the value from the database (or other source). `GlobalSetting` implements this to query the DB. --- ### 3. Invariants - **Singleton & Thread Safety**: `SettingsDB` is a singleton with lazy initialization. All public static methods (`GetGlobalValue`, `SetGlobalValue`, etc.) are guarded by a `lock (LOCK_OBJECT)` on the singleton instance, ensuring thread-safe access to `_settingsLookup` and DB operations. - **Global Scope**: `GlobalSetting` instances are always associated with `UserId = "SYSTEM"` and `PropertyType = PropertyTypes.Global` (value `2`). - **Default Fallback**: If a setting does not exist in the database, `GetPropertyValue` falls back to the provided `defaultValue`, stores it in the DB via `StoreInDB()`, and returns it. - **Caching**: Once instantiated, a `Setting` object is cached in `SettingsDB._settingsLookup`. Subsequent lookups for the same `id` reuse the cached instance. - **DB Schema Assumption**: The module assumes: - A stored procedure `sp_SettingsGet` exists, accepting `@UserId` (NVARCHAR) and `@PropertyId` (NVARCHAR), returning a result set with a column named `PropertyValue` (via `DbOperations.Settings.UserFields.PropertyValue`). - A stored procedure `sp_SettingsUpdateInsert` exists, accepting parameters: `@PropertyId`, `@PropertyType`, `@PropertyValue`, `@UserId`, `@new_id` (OUTPUT), `@errorNumber` (OUTPUT), `@errorMessage` (OUTPUT). All string parameters are NVARCHAR(255). --- ### 4. Dependencies #### **Dependencies *of* this module:** - `System.Data` and `System.Data.SqlClient` (for `SqlDataAdapter`, `SqlCommand`, `SqlParameter`, `SqlDbType`, etc.) - `DbOperations` (static class, not shown) — provides: - `GetSQLCommand(bool)` → returns `SqlCommand` - `Connection.QueryDataSet(SqlCommand)` → returns `DataSet` - `Settings.UserFields.PropertyValue` → string constant for column name (e.g., `"PropertyValue"`) - `DbOperationsEnum.StoredProcedure.sp_SettingsGet`, `sp_SettingsUpdateInsert` → enum values for stored procedure names. #### **Dependencies *on* this module:** - Any code requiring global configuration (e.g., import batch size, timeout, feature flags) calls `SettingsDB.GetGlobalValue(...)` or `GetGlobalValueBool(...)`. #### **Inferred callers:** - `DatabaseImporter` module (e.g., import pipeline components that read global settings like `"MaxRetryCount"`, `"DefaultSchema"`). --- ### 5. Gotchas - **Exception Handling is Minimal**: `GetPropertyValue` and `StoreInDB` both catch `Exception` and silently fall back to `defaultValue` or do nothing, respectively. No logging is active (commented-out `APILogger.LogException` suggests future intent). This makes debugging DB issues difficult. - **No Validation on Value Length**: `PropertyValue` is stored as `NVARCHAR(255)` in DB calls, but no validation occurs in `Setting` or `GlobalSetting`. Passing a >255-character value may cause a DB error (silently ignored in `StoreInDB`). - **Race Condition in Initialization (Low Risk)**: While `GetGlobalValue` locks before checking `_settingsLookup`, the *first* call for a new `id` creates a new `GlobalSetting` *inside* the lock. However, `GlobalSetting` constructor calls `GetPropertyValue`, which performs a DB round-trip *while holding the lock*. This can cause contention if many settings are requested concurrently for the first time. - **Hardcoded `"SYSTEM"` User**: `GlobalSetting` hardcodes `UserId = "SYSTEM"`. This is not configurable and assumes all global settings are owned by a system user. - **`_allGlobalSetting` Cache is Unused**: The `GetPropertyValue` method contains commented-out code for a `_allGlobalSetting` cache. This suggests a previous optimization attempt that was reverted or incomplete — the current implementation hits the DB on *every* first access for a new `id`. - **Culture-Specific Boolean Parsing**: `GetGlobalValueBool` uses `defaultValue.ToString(CultureInfo.InvariantCulture)` for the fallback string, but `bool.TryParse` is culture-insensitive for `"True"/"False"`. This is safe, but the use of `InvariantCulture` here is redundant and could mislead. - **No Explicit Disposal of `Setting` Instances**: `Setting` instances are stored in `_settingsLookup` and never removed. If settings are frequently added/removed at runtime, this could lead to memory leaks. - **No Distinction Between `null` and Empty String**: If the DB stores `NULL` for `PropertyValue`, `Convert.ToString(...)` returns `""` (empty string), not `null`. This may or may not be intended. --- *Documentation generated from provided source files. No external assumptions or behaviors inferred beyond what is explicitly present.*