Files
DP44/enriched-qwen3-coder-next/DataPRO/Modules/Database/DatabaseServices/ViewModel.md
2026-04-17 14:55:32 -04:00

206 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
source_files:
- DataPRO/Modules/Database/DatabaseServices/ViewModel/DatabaseStatusBarViewModel.cs
- DataPRO/Modules/Database/DatabaseServices/ViewModel/DatabaseSwitchViewModel.cs
- DataPRO/Modules/Database/DatabaseServices/ViewModel/DatabaseCopyViewModel.cs
generated_at: "2026-04-16T04:35:56.029845+00:00"
model: "Qwen/Qwen3-Coder-Next-FP8"
schema_version: 1
sha256: "f187d4b018ffae25"
---
# Database Services ViewModels Documentation
## 1. Purpose
This module provides UI-facing view models (`DatabaseStatusBarViewModel`, `DatabaseSwitchViewModel`, and `DatabaseCopyViewModel`) that manage database connection state, user interaction for database switching/copying, and status reporting in the DataPRO application. These view models coordinate database operations (local vs. remote), handle UI state (busy indicators, progress bars, notifications), and integrate with Prisms event aggregation and Unity DI container for decoupled communication with other system components. They serve as the bridge between low-level database operations (e.g., `DbOperations`, `DatabaseServices`) and the WPF UI layer.
---
## 2. Public Interface
### `DatabaseStatusBarViewModel`
- **`string ActiveDbName { get; }`**
Returns a string representing the active database: `"Local"` for `DbType.LocalOnly`, `ServerName` for `DbType.RemoteOnly`, or `ServerName`/`"Local"` conditionally for `DbType.RemoteLocalHybrid`.
- **`Brush BackgroundBrush { get; }`**
Returns `Brushes.Red` when `DatabaseType == DbType.RemoteLocalHybrid` and `RemoteConnected == false`; otherwise `Brushes.Transparent`.
- **`bool RemoteConnected { get; }`**
Returns the value of `DbOperations._usingCentralizedDB`.
- **`string ServerName { get; private set; }`**
Holds the remote server name; updated via `InitializeValues` or `OnDbEvent`.
- **`void InitializeValues(DbType dbType, string serverName, bool remoteConnected)`**
Sets `DatabaseType`, `ServerName`, and triggers property change notifications for `ActiveDbName` and `BackgroundBrush`.
- **`void OnDbEvent(DbStatusArg args)`**
Internal event handler for `DbStatusEvent`; updates `ServerName` and notifies changes to `ActiveDbName`/`BackgroundBrush` when `args.Status == LegacyStatus`.
- **`bool IsBusy { get; set; }`**
Binds to UI busy indicator; updated via `OnBusyIndicatorNotification`.
- **`bool IsMenuIncluded`, `bool IsNavigationIncluded`**
UI state flags for menu/navigation visibility; support INotifyPropertyChanged.
- **`InteractionRequest<Notification> NotificationRequest { get; }`**
Prism interaction request used to show notification popups.
- **`InteractionRequest<Confirmation> ConfirmationRequest { get; }`**
Prism interaction request used to show confirmation dialogs.
- **`IDatabaseStatusBarView View { get; set; }`**
Reference to the associated view; `View.DataContext` is set to `this` in constructor.
- **Constructors**
- `DatabaseStatusBarViewModel(IDatabaseStatusBarView view, IRegionManager regionManager, IEventAggregator eventAggregator, IUnityContainer unityContainer)`
Registers event subscriptions for `RaiseNotification`, `BusyIndicatorChangeNotification`, and `DbStatusEvent`.
- `DatabaseStatusBarViewModel()`
Parameterless constructor (used for design-time or manual instantiation).
- **Lifecycle methods (no-op)**
`Unset()`, `Cleanup()`, `CleanupAsync()`, `Initialize()`, `Initialize(object)`, `Initialize(object, object)`, `InitializeAsync()`, `InitializeAsync(object)`, `Activated()` — all currently empty.
### `DatabaseSwitchViewModel`
- **`bool RemoteIsActive { get; }`**
Returns `DbOperations._usingCentralizedDB`.
- **`void SwitchRemote()`**
Attempts to switch to remote database:
1. Publishes `AppStatusArg.Busy`.
2. Calls `DatabaseServices.SetupForRemoteDb(...)` with stored credentials.
3. Validates connection via `SimpleDbTest()`.
4. On failure: publishes `DbStatusEvent` with `FailedToConnectToRemote`, calls `SwitchLocal()`, logs exception.
5. On success: publishes `DbStatusEvent.LegacyStatus`, `AppStatusArg.Available`, and `LogoutUserEvent` (reason: `DatabaseSwitch`).
- **`void SwitchLocal()`**
Switches to local database:
1. Checks local DB files exist via `CheckLocalDatabaseFilesExist(...)`.
2. Publishes `AppStatusArg.Busy`.
3. Calls `DatabaseServices.SetupLocal(...)`.
4. Publishes `DbStatusEvent.LegacyStatus`, `AppStatusArg.Available`, and `LogoutUserEvent`.
- **`void InitializeDbSettings(string defaultDbName, string dbHost, bool ntlmAuthentication, string dbUser, string dbPassword)`**
Stores connection settings for later use in `SwitchRemote()`.
- **Properties**: `DefaultDbName`, `DbHost`, `NTLMAuthentication`, `DbUser`, `DbPassword` (all `private set`).
- **`bool IsBusy`, `IsMenuIncluded`, `IsNavigationIncluded`**
Same semantics as `DatabaseStatusBarViewModel`.
- **Constructors & Lifecycle methods**
Same as `DatabaseStatusBarViewModel`; constructor subscribes to `RaiseNotification` and `BusyIndicatorChangeNotification`.
### `DatabaseCopyViewModel`
- **`bool CopyEnabled { get; }`**
Returns `true` only if `DatabaseType == DbType.RemoteLocalHybrid` and `DbOperations._usingCentralizedDB == true`.
- **`void CopyDatabase()`**
Triggers `CopyFunc()` on a background task (`Task.Run`). Publishes `AppStatusArg.Busy` before and `AppStatusArg.Available` after.
- **`void InitializeState(DbType dbType, string dbName)`**
Sets `DatabaseType` and `DbName`, publishes initial `ProgressBarEvent` for both progress bars (collapsed), and notifies `CopyEnabled`.
- **`string DbName { get; private set; }`**
Name of the database being copied.
- **`bool IsCopyVisible { get; set; }`**
Controls visibility of the copy UI section.
- **`IStatusAndProgressBarView OverallProgressBarView`, `IStatusAndProgressBarView CurrentTaskProgressBarView`**
References to progress bar views resolved during `InitializeAsync()`.
- **`Task InitializeAsync()`**
Resolves and configures two `IStatusAndProgressBarView` instances:
- One for `OverallTaskBar` (named `"OverallStatus"`).
- One for `CurrentTaskBar` (named `"CurrentTaskStatus"`).
Each is bound to a shared `IStatusAndProgressBarViewModel` instance.
- **`void OnRaiseNotification(NotificationContentEventArgs)`**
Wraps event args into `Notification` and raises `NotificationRequest`.
- **`void OnBusyIndicatorNotification(bool)`**
Sets `IsBusy`.
- **`bool IsBusy`, `IsMenuIncluded`, `IsNavigationIncluded`, `IsDirty`**
Same semantics as above.
- **Internal helper methods (private)**
- `CopyFunc()`: Main copy logic:
1. Backs up local DB.
2. Disables constraints.
3. Copies all tables in `_allDBTables` via `CopyRemoteTable(...)`.
4. Fixes `Channels.DASId = 0 → NULL`.
5. Re-enables constraints.
6. Restores local DB on failure.
7. Publishes progress via `ProgressBarEvent`.
- `CopyRemoteTable(string tableName, bool bIndentityTable)`: Fetches all rows from remote DB, stores in memory.
- `InsertIntoLocalTable(...)`: Inserts rows in batches (max 20 rows/batch to avoid SQL parameter limit), handles `IDENTITY_INSERT` for tables in `_tablesWithIdentities`.
- `SetStatus(string bar, double percentage, string text)`: Publishes `ProgressBarEvent`.
- **Constants & Data**
- `MAX_BATCH_SIZE = 20`
- `_allDBTables`: List of 72 table names (includes duplicates like `"tblDataPRODbVersion"` and `"DataPRODbVersion"`).
- `_tablesWithIdentities`: HashSet of 58 table names requiring `IDENTITY_INSERT ON/OFF`.
---
## 3. Invariants
- **`RemoteConnected` is derived solely from `DbOperations._usingCentralizedDB`** — no local state overrides it.
- **`ActiveDbName` and `BackgroundBrush` depend on `DatabaseType` and `RemoteConnected`** — their values are recalculated only when `DatabaseType` or `ServerName` changes (via `InitializeValues` or `OnDbEvent`).
- **Progress bars are always reset to collapsed/zero on completion/failure** — `CopyFunc()` publishes `ProgressBarEvent` with `Visibility.Collapsed` in `finally`.
- **`CopyDatabase()` runs asynchronously** — `Task.Run` is used explicitly; no `async/await` is used internally.
- **`DatabaseCopyViewModel` requires `InitializeAsync()` to be called before `CopyDatabase()`** — otherwise `OverallProgressBarView`/`CurrentTaskProgressBarView` remain `null`.
- **`DatabaseSwitchViewModel.SwitchRemote()` and `SwitchLocal()` always trigger `LogoutUserEvent`** — user session is invalidated after any database switch.
- **`DatabaseStatusBarViewModel.OnDbEvent(...)` only handles `LegacyStatus`** — other `DbStatusArg.EventTypes` are ignored.
---
## 4. Dependencies
### Internal Dependencies (from source):
- **`DTS.Common.*`**:
- `DTS.Common.Enums.Database.DbType`
- `DTS.Common.Events.*` (`RaiseNotification`, `BusyIndicatorChangeNotification`, `DbStatusEvent`, `AppStatusEvent`, `PageErrorEvent`, `LogoutUserEvent`)
- `DTS.Common.Storage.DatabaseServices` (`SetupForRemoteDb`, `SimpleDbTest`, `SetupLocal`, `BackupLocalDatabase`, `RestoreLocalDatabase`, `LOCAL_DB_FOLDER`)
- `DTS.Common.Storage.DatabaseServices` (via `DbOperations`, `LocalOnlyOperations`)
- `DTS.Common.Interface.Database.*` (e.g., `IDatabaseStatusBarView`, `IDatabaseCopyViewModel`)
- `DTS.Common.Interface.*` (e.g., `IStatusAndProgressBarView`)
- `DTS.Common.Utilities.Logging.APILogger`
- `DTS.Common.Interactivity.*` (`InteractionRequest`, `Notification`, `Confirmation`)
- **Prism Framework**:
- `Prism.Events.IEventAggregator`, `Prism.Regions.IRegionManager`
- `Prism.Commands`, `Prism.Interactivity.InteractionRequest`
- **Unity DI Container** (`IUnityContainer`)
- **WPF** (`System.Windows.Media.Brush`, `System.Windows.Visibility`)
### External Dependencies:
- **SQL Server** (via `System.Data.SqlClient`, `DbOperations.Connection`, `LocalOnlyOperations`)
- **`Resources.StringResources`** (localized strings: `"Local"`, `"CopyingTable"`, `"ClearingLocalDb"`, `"EnablingConstraints"`, `"SwitchFileNotFound"`)
### Inferred Consumers:
- Views (`IDatabaseStatusBarView`, `IDatabaseSwitchView`, `IDatabaseCopyView`) bind to these view models.
- Event publishers (`RaiseNotification`, `DbStatusEvent`, `AppStatusEvent`, etc.) drive view model state changes.
- `DatabaseServices` layer (`DbOperations`, `LocalOnlyOperations`) is called directly by these view models.
---
## 5. Gotchas
- **`DatabaseStatusBarViewModel` has two constructors** — the parameterless one does not subscribe to events, so `OnDbEvent`, `OnBusyIndicatorNotification`, and `OnRaiseNotification` will not be triggered if used. This is likely a design flaw or legacy artifact.
- **`DatabaseStatusBarViewModel.OnDbEvent` only handles `LegacyStatus`** — other status types (e.g., `FailedToConnectToRemote`) are silently ignored.
- **`DatabaseCopyViewModel.CopyFunc()` loads entire remote tables into memory** — `CopyRemoteTable` fetches all rows via `QueryDataSet` before copying. This may cause OOM for large tables.
- **`DatabaseCopyViewModel` uses hardcoded table list (`_allDBTables`)** — not dynamically fetched from DB schema. Duplicates exist (`"DataPRODbVersion"` and `"tblDataPRODbVersion"`), and missing tables will cause copy failures.
- **Batch size (`MAX_BATCH_SIZE = 20`) is arbitrary** — comment notes it was tuned empirically to avoid SQL parameter limits (2100), but no validation ensures column count × rows ≤ 2100.
- **`DatabaseSwitchViewModel.SwitchRemote()` calls `SwitchLocal()` on failure** — this may cause cascading failures or confusing UI state if local DB is also unavailable.
- **`DatabaseStatusBarViewModel.ServerName` is updated only in `OnDbEvent` for `LegacyStatus`** — if `InitializeValues` is not called first, `ServerName` remains `null`/empty, leading to incorrect `ActiveDbName`.
- **`DatabaseCopyViewModel.InitializeAsync()` resolves views/models twice** — two separate `Resolve` calls for `IStatusAndProgressBarView`/`IStatusAndProgressBarViewModel` per progress bar, potentially creating duplicate view model instances.
- **No cancellation support** — `CopyDatabase()` and `SwitchRemote()`/`SwitchLocal()` lack cancellation tokens or progress callbacks for user-initiated aborts.
- **`DbOperations._usingCentralizedDB` is a static field** — shared across the app domain; changes in one view model affect others unexpectedly.
- **`DatabaseStatusBarViewModel.ActiveDbName` returns `""` for unhandled `DbType`** — no fallback or exception on unknown types.
- **`DatabaseCopyViewModel` uses `sp_msforeachtable`** — undocumented, unsupported SQL Server stored procedure; may break on future SQL Server versions or non-standard DB configurations.