Files

193 lines
13 KiB
Markdown
Raw Permalink Normal View History

2026-04-17 14:55:32 -04:00
---
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-17T15:41:29.202299+00:00"
model: "zai-org/GLM-5-FP8"
schema_version: 1
sha256: "f011aeacca70c45c"
---
# Database ViewModels Documentation
## 1. Purpose
This module provides three MVVM ViewModels for database management within the `DatabaseServices` namespace:
- **DatabaseStatusBarViewModel**: Manages the database status bar UI, displaying the active database connection (Local vs Remote) and providing visual feedback (red background when disconnected from remote in hybrid mode).
- **DatabaseSwitchViewModel**: Handles switching between local and remote database connections, including connection testing, authentication setup, and forcing user re-login after database switches.
- **DatabaseCopyViewModel**: Implements database copy functionality to synchronize a remote database to a local database, including table-by-table copying with identity column handling and constraint management.
All three ViewModels follow the Prism MVVM pattern, use MEF for dependency injection with shared creation policy, and integrate with the application's event aggregation system.
---
## 2. Public Interface
### DatabaseStatusBarViewModel
**Implements:** `IDatabaseStatusBarViewModel`
| Member | Signature | Description |
|--------|-----------|-------------|
| `View` | `public IDatabaseStatusBarView View { get; set; }` | The associated view instance; DataContext is set to `this` in constructor. |
| `DatabaseType` | `public DbType DatabaseType { get; private set; }` | The configured database type (LocalOnly, RemoteOnly, RemoteLocalHybrid). |
| `ServerName` | `public string ServerName { get; private set; }` | Name of the database server; "Local" when not remote connected. |
| `RemoteConnected` | `public bool RemoteConnected => DbOperations._usingCentralizedDB;` | Indicates if currently connected to centralized/remote database. |
| `ActiveDbName` | `public string ActiveDbName { get; }` | Computed display name based on DatabaseType and connection state. Returns localized "Local" string or server name. |
| `BackgroundBrush` | `public Brush BackgroundBrush { get; }` | Returns `Brushes.Red` when hybrid mode is disconnected from remote; otherwise `Brushes.Transparent`. |
| `InitializeValues` | `public void InitializeValues(DbType dbType, string serverName, bool remoteConnected)` | Initializes the ViewModel's state and triggers PropertyChanged for `ActiveDbName` and `BackgroundBrush`. |
| `OnPropertyChanged` | `public void OnPropertyChanged(string propertyName)` | Raises the `PropertyChanged` event. |
| `NotificationRequest` | `public InteractionRequest<Notification> NotificationRequest { get; }` | Prism interaction request for notifications. |
| `ConfirmationRequest` | `public InteractionRequest<Confirmation> ConfirmationRequest { get; }` | Prism interaction request for confirmations. |
| `IsBusy` | `public bool IsBusy { get; set; }` | Bound to busy indicator state. |
| `IsMenuIncluded` | `public bool IsMenuIncluded { get; set; }` | Controls menu visibility. |
| `IsNavigationIncluded` | `public bool IsNavigationIncluded { get; set; }` | Controls navigation visibility. |
| `IsDirty` | `public bool IsDirty { get; private set; }` | Tracks unsaved changes state. |
| `Cleanup` / `CleanupAsync` | `public void Cleanup()` / `public Task CleanupAsync()` | No-op cleanup methods. |
| `Initialize` overloads | `void Initialize()`, `void Initialize(object)`, `void Initialize(object, object)` | No-op initialization methods. |
| `InitializeAsync` overloads | `Task InitializeAsync()`, `Task InitializeAsync(object)` | Return `Task.CompletedTask`. |
| `Activated` | `public void Activated()` | No-op activation method. |
| `Unset` | `public void Unset()` | No-op unset method. |
**Constructor:**
```csharp
public DatabaseStatusBarViewModel(
IDatabaseStatusBarView view,
IRegionManager regionManager,
IEventAggregator eventAggregator,
IUnityContainer unityContainer)
```
---
### DatabaseSwitchViewModel
**Implements:** `IDatabaseSwitchViewModel`
| Member | Signature | Description |
|--------|-----------|-------------|
| `View` | `public IDatabaseSwitchView View { get; set; }` | The associated view instance. |
| `DefaultDbName` | `public string DefaultDbName { get; private set; }` | Default database name for connections. |
| `DbHost` | `public string DbHost { get; private set; }` | Remote database host address. |
| `NTLMAuthentication` | `public bool NTLMAuthentication { get; private set; }` | Whether NTLM authentication is enabled. |
| `DbUser` | `public string DbUser { get; private set; }` | Database username for SQL authentication. |
| `DbPassword` | `public string DbPassword { get; private set; }` | Database password for SQL authentication. |
| `RemoteIsActive` | `public bool RemoteIsActive => DbOperations._usingCentralizedDB;` | Indicates if remote database is currently active. |
| `SwitchRemote` | `public void SwitchRemote()` | Switches to remote database connection. Tests connection, falls back to local on failure, publishes `DbStatusEvent` and `LogoutUserEvent`. |
| `SwitchLocal` | `public void SwitchLocal()` | Switches to local database. Validates local files exist, publishes status events and forces logout. |
| `InitializeDbSettings` | `public void InitializeDbSettings(string defaultDbName, string dbHost, bool ntlmAuthentication, string dbUser, string dbPassword)` | Stores database connection settings for use by switch methods. |
| `IsBusy`, `IsMenuIncluded`, `IsNavigationIncluded`, `IsDirty` | Same as DatabaseStatusBarViewModel | Standard ViewModel properties. |
| `NotificationRequest`, `ConfirmationRequest` | Same as DatabaseStatusBarViewModel | Prism interaction requests. |
| Lifecycle methods | Same pattern as DatabaseStatusBarViewModel | `Cleanup`, `CleanupAsync`, `Initialize*`, `Activated`, `Unset` are no-ops or return completed tasks. |
**Constructor:**
```csharp
public DatabaseSwitchViewModel(
IDatabaseSwitchView view,
IRegionManager regionManager,
IEventAggregator eventAggregator,
IUnityContainer unityContainer)
```
---
### DatabaseCopyViewModel
**Implements:** `IDatabaseCopyViewModel`
| Member | Signature | Description |
|--------|-----------|-------------|
| `View` | `public IDatabaseCopyView View { get; set; }` | The associated view instance. |
| `DatabaseType` | `public DTS.Common.Enums.Database.DbType DatabaseType { get; private set; }` | Current database type configuration. |
| `DbName` | `public string DbName { get; private set; }` | Name of the database being copied. |
| `CopyEnabled` | `public bool CopyEnabled => DatabaseType == DbType.RemoteLocalHybrid && DbOperations._usingCentralizedDB;` | Copy is only enabled in hybrid mode when connected to remote. |
| `IsCopyVisible` | `public bool IsCopyVisible { get; set; }` | Controls visibility of copy UI; defaults to `true`. |
| `OverallProgressBarView` | `public IStatusAndProgressBarView OverallProgressBarView { get; private set; }` | Progress bar view for overall copy progress. |
| `CurrentTaskProgressBarView` | `public IStatusAndProgressBarView CurrentTaskProgressBarView { get; private set; }` | Progress bar view for current table copy progress. |
| `CopyDatabase` | `public void CopyDatabase()` | Initiates async database copy via `Task.Run(() => CopyFunc())`. Publishes `AppStatusEvent.Busy`. |
| `InitializeState` | `public void InitializeState(DTS.Common.Enums.Database.DbType dbType, string dbName)` | Sets up initial state, resets progress bars, triggers `OnPropertyChanged("CopyEnabled")`. |
| `InitializeAsync` | `public Task InitializeAsync()` | Resolves and initializes progress bar views via Unity container. |
| `_allDBTables` | `private static readonly List<string>` | Hardcoded list of 73 database table names to copy. |
| `_tablesWithIdentities` | `private static readonly HashSet<string>` | Hardcoded set of 48 table names that have identity columns. |
| `MAX_BATCH_SIZE` | `private const int MAX_BATCH_SIZE = 20;` | Maximum rows per batch insert to avoid SQL Server's 2100 parameter limit. |
| `CurrentTaskBar` | `private const string CurrentTaskBar = "CurrentTaskStatus";` | Identifier for current task progress bar. |
| `OverallTaskBar` | `private const string OverallTaskBar = "OverallStatus";` | Identifier for overall progress bar. |
| Lifecycle methods | Same pattern as other ViewModels | Standard no-op implementations except `InitializeAsync`. |
**Constructor:**
```csharp
public DatabaseCopyViewModel(
IDatabaseCopyView view,
IRegionManager regionManager,
IEventAggregator eventAggregator,
IUnityContainer unityContainer)
```
---
## 3. Invariants
### DatabaseStatusBarViewModel
- `ActiveDbName` returns empty string for unhandled `DbType` values (not LocalOnly, RemoteOnly, or RemoteLocalHybrid).
- `BackgroundBrush` only returns `Brushes.Red` for `DbType.RemoteLocalHybrid` when `RemoteConnected` is false; all other cases return `Brushes.Transparent`.
- `RemoteConnected` is directly coupled to `DbOperations._usingCentralizedDB` static field.
### DatabaseSwitchViewModel
- `SwitchRemote` always publishes `LogoutUserEvent` with reason `DatabaseSwitch` on success.
- `SwitchRemote` calls `SwitchLocal()` as fallback if connection test fails.
- `SwitchLocal` checks for local database file existence before proceeding; returns early with error if files not found.
- `SwitchLocal` always publishes `LogoutUserEvent` with reason `DatabaseSwitch` on success.
### DatabaseCopyViewModel
- `CopyEnabled` is only true when `DatabaseType == DbType.RemoteLocalHybrid` AND `DbOperations._usingCentralizedDB` is true.
- Copy operation disables constraints before copying and re-enables them after.
- If copy fails, attempts to restore from backup via `DTS.Common.Storage.DatabaseServices.RestoreLocalDatabase(DbName)`.
- Batch inserts are limited to `MAX_BATCH_SIZE` (20 rows) or when parameter count would exceed 2100.
- Identity insert is enabled/disabled per batch for tables in `_tablesWithIdentities`.
- `DASId` columns with value 0 are explicitly set to NULL in the Channels table after copy.
---
## 4. Dependencies
### External Dependencies (from imports)
- **Prism Framework:** `Prism.Events`, `Prism.Regions`, `Prism.Commands` - Event aggregation, region management, commanding
- **Unity Container:** `Unity` - Dependency injection container
- **MEF:** `System.ComponentModel.Composition` - Part creation policy
- **WPF:** `System.Windows.Media`, `System.ComponentModel` - UI types, INotifyPropertyChanged
- **DTS.Common.Enums.Database:** `DbType` enum
- **DTS.Common.Events:** `RaiseNotification`, `BusyIndicatorChangeNotification`, `AppStatusEvent`, `AppStatusArg`, `ProgressBarEvent`, `ProgressBarEventArg`, `PageErrorEvent`, `PageErrorArg`
- **DTS.Common.Events.Database:** `DbStatusEvent`, `DbStatusArg`, `LogoutUserEvent`, `LogoutUserArg`
- **DTS.Common.Interactivity:** `InteractionRequest<T>`, `Notification`, `Confirmation`, `NotificationContentEventArgs`
- **DTS.Common.Interface.Database:** `IDatabaseStatusBarView`, `IDatabaseSwitchView`, `IDatabaseCopyView`, `IDatabaseStatusBarViewModel`, `IDatabaseSwitchViewModel`, `IDatabaseCopyViewModel`
- **DTS.Common.Interface:** `IStatusAndProgressBarView`, `IStatusAndProgressBarViewModel`
- **DTS.Common.Storage:** `DbOperations`, `LocalOnlyOperations`, `DatabaseServices` (static class)
- **DTS.Common.Utilities.Logging:** `APILogger`
- **DTS.Common.Utils.Database:** `CheckLocalDatabaseFilesExist`
- **Resources.StringResources:** Localized strings
### Static Couplings
- `DbOperations._usingCentralizedDB` - Static field accessed directly by all three ViewModels
- `DbOperations.Connection.Server` - Server name accessed directly
- `DbOperations.GetSQLCommand()` - SQL command creation for remote DB
- `LocalOnlyOperations.GetSQLCommand()` - SQL command creation for local DB
- `LocalOnlyOperations.BeginStatement`, `LocalOnlyOperations.CommitStatement` - Transaction statements
- `LocalOnlyOperations.CreateParam()` - Parameter creation helper
---
## 5. Gotchas
### XML Documentation Mismatch
- `DatabaseStatusBarViewModel` and `DatabaseSwitchViewModel` XML summary comments state "this class handles DatabaseCopy functionality" which is incorrect (copy-paste error from `DatabaseCopyViewModel`).
### Parameterless Constructors
- All three ViewModels have public parameterless constructors in addition to the DI constructor. The parameterless constructors perform no initialization, which could lead to null reference exceptions if used incorrectly.
### Static Table Lists
- `DatabaseCopyViewModel._allDBTables` and `_tablesWithIdentities` are hardcoded lists. Any database schema changes require code updates. Comment in source states: "I'd like to do this through SQL, but ran into problems".
### Thread Safety Concerns
- `DatabaseCopyViewModel.CopyDatabase()` uses `Task.Run()` to execute `CopyFunc()` on a background thread, but `SetStatus()` publishes UI events directly. The `BusyIndicatorChangeNotification` subscription in `DatabaseStatusBarViewModel` uses `ThreadOption.PublisherThread` with `keepSubscriberReferenceAlive: true