183 lines
13 KiB
Markdown
183 lines
13 KiB
Markdown
---
|
|
source_files:
|
|
- DataPRO/Modules/Database/DatabaseMigrator/MigrateDatabase.cs
|
|
- DataPRO/Modules/Database/DatabaseMigrator/MigrationForm.Designer.cs
|
|
- DataPRO/Modules/Database/DatabaseMigrator/MigrationForm.cs
|
|
generated_at: "2026-04-16T04:35:00.160493+00:00"
|
|
model: "Qwen/Qwen3-Coder-Next-FP8"
|
|
schema_version: 1
|
|
sha256: "ea93d67370ed0c49"
|
|
---
|
|
|
|
# DatabaseMigrator Module Documentation
|
|
|
|
## 1. Purpose
|
|
|
|
This module provides a Windows Forms-based utility for upgrading a local DataPRO database to a specified target version. It serves as a standalone migration tool that interacts with SQL Server Express LocalDB instances, validates the current database version, creates backups before migration, executes version-specific upgrade scripts via the `DbOperations.Connection.UpgradeVersionsIfNeeded` method, and handles error reporting and user interaction. It is intended for use during application upgrades where the embedded database schema has changed, ensuring safe and traceable schema evolution.
|
|
|
|
## 2. Public Interface
|
|
|
|
The module exposes only one public class: `MigrationForm`. All other types (`MigrateDatabase`, `DbOperations`, `MigrationResult`, etc.) are referenced but not defined in the provided source.
|
|
|
|
### `MigrationForm(string targetDir)`
|
|
**Namespace:** `DatabaseMigrator`
|
|
**Inherits:** `System.Windows.Forms.Form`
|
|
**Behavior:** Constructor that initializes the form UI and stores the `_targetDir` path (used to locate database files and configuration). It does not perform any migration logic itself.
|
|
|
|
### `MigrationForm.buttonOK_Click(object sender, EventArgs e)`
|
|
**Access:** `private` (event handler)
|
|
**Behavior:** Handles the OK button click. Performs the following sequence:
|
|
1. Queries the current database version via `GetDatabaseVersion(true)`.
|
|
2. Compares current version to `_desiredDatabaseVersion`.
|
|
3. If versions match or current > desired, shows a warning message.
|
|
4. If migration is needed:
|
|
- Calls `CopyLocalDB()` to create a backup.
|
|
- Invokes `DbOperations.Connection.UpgradeVersionsIfNeeded(...)` with hardcoded arguments (`"DataPRO"`, `"previousdir"`, `"targetdir"`, `"DataPRO.exe"`, `"applicationSettings"`).
|
|
- Displays success or failure via `MessageBox`.
|
|
5. Closes the form.
|
|
|
|
### `MigrationForm.buttonCancel_Click(object sender, EventArgs e)`
|
|
**Access:** `private` (event handler)
|
|
**Behavior:** Closes the form without performing any migration.
|
|
|
|
### `MigrationForm.GetDatabaseVersion(bool usingLocalDatabase)`
|
|
**Access:** `private`
|
|
**Behavior:** Determines the current database version by:
|
|
- Attempting to run the stored procedure `sp_DbVersionGet` (via `DbOperations.GetSQLCommand(true)`).
|
|
- Parsing the returned version numbers and returning the maximum.
|
|
- Falls back to returning `0` on failure (commented-out SQLite fallback logic is present but inactive).
|
|
- If `localSQLLocalDbDataExists` is true, calls `InstallDatabase()` first to set up the LocalDB instance.
|
|
|
|
### `MigrationForm.CopyLocalDB()`
|
|
**Access:** `private`
|
|
**Behavior:** Creates a timestamped backup of the `DataPRO.mdf` and `DataPRO_log.ldf` files in the `_targetDir`. It:
|
|
- Calls `ProcessSqlLocalDbCommand(...StopDataProInstance...)` to stop the LocalDB instance.
|
|
- Copies the `.mdf` and `.ldf` files to new filenames with suffix `_YYYY_MM_DD HH_MM`.
|
|
- Returns `true` if `.mdf` copy succeeds (`.ldf` copy is not checked for success).
|
|
|
|
### `MigrationForm.InstallDatabase()`
|
|
**Access:** `private`
|
|
**Behavior:** Sets up a fresh LocalDB instance named `(localdb)\DataPROInstance` by:
|
|
- Setting `DbOperations._usingMSSQL = true`, `_usingCentralizedDB = false`, `_usingNTLMAuthentication = true`.
|
|
- Executing a sequence of `sqllocaldb.exe` commands via `ProcessSqlLocalDbCommand(...)`:
|
|
- Stop instance
|
|
- Delete instance
|
|
- Create instance
|
|
- Start instance
|
|
- Attaching two databases (`DataPRO` and `ISO`) using `AttachDatabase(...)`, which internally calls `sqlcmd.exe` via a batch file.
|
|
|
|
### `MigrationForm.SetMigrationStatus(string migrationStatus)`
|
|
**Access:** `private`
|
|
**Behavior:** Updates the `MigrationStatusLabel` UI element with the given status string and forces a UI refresh.
|
|
|
|
### `MigrationForm.SetStatus(string status, bool output = false)`
|
|
**Access:** `private`
|
|
**Behavior:** Updates the `statusTextLabel` UI element with the given status string and forces a UI refresh. The `output` parameter is unused.
|
|
|
|
### `MigrationForm.numericUpDownDesiredVersion_ValueChanged(object sender, EventArgs e)`
|
|
**Access:** `private` (event handler)
|
|
**Behavior:** Updates `_desiredDatabaseVersion` to the current value of `numericUpDownDesiredVersion`.
|
|
|
|
### `MigrationForm.LocalDataExists()`
|
|
**Access:** `private`
|
|
**Behavior:** Checks for existence of database files in `_targetDir\LocalDb\`:
|
|
- First checks for `DataPRO.mdf` → sets `localSQLLocalDbDataExists = true`.
|
|
- Else checks for `DataPRO.db` (SQLite) → sets `localSQLiteDataExists = true`.
|
|
- Returns `true` if either exists.
|
|
|
|
### `MigrationForm.MigrationForm_Load(object sender, EventArgs e)`
|
|
**Access:** `private` (event handler)
|
|
**Behavior:** On form load:
|
|
- Sets `numericUpDownDesiredVersion` range to `[61, DbOperations.CURRENT_DB_VERSION]`.
|
|
- Sets initial value to `DbOperations.CURRENT_DB_VERSION`.
|
|
- Calls `LocalDataExists()` to detect existing database type.
|
|
- Populates `TbDatabasePath.Text` with the full path to `DataPRO.mdf` if LocalDB data exists.
|
|
|
|
### `MigrationForm.ConvertMigrationResultToSetting(MigrationResult result)`
|
|
**Access:** `private`
|
|
**Behavior:** Maps `MigrationResult` enum values to user-facing strings using `Settings.Default.*` resources. Currently only handles `WarningAllowStreamingModesWasNotMigrated`.
|
|
|
|
### `MigrationForm.ConvertResultAndDisplay(MigrationResult result)`
|
|
**Access:** `private`
|
|
**Behavior:** Calls `ConvertMigrationResultToSetting(...)` and displays the result in a `MessageBox`.
|
|
|
|
### `MigrationForm.ProcessSqlLocalDbCommand(string command)` *(static)*
|
|
**Access:** `private static`
|
|
**Behavior:** Executes a command string via `sqllocaldb.exe`:
|
|
- Locates the highest installed LocalDB version via registry (`HKLM\...\LocalDB\InstalledVersions`).
|
|
- Constructs full path to `SqlLocalDB.exe`.
|
|
- Invokes `SqlCommandProcessor(...)` to run the command and capture output.
|
|
|
|
### `MigrationForm.AttachDatabase(string targetDir, string dbName, string sqlDbFileName, string sqlLogFileName)` *(static)*
|
|
**Access:** `private static`
|
|
**Behavior:** Attaches a database using a batch file (`Settings.Default.AttachDBsbat`) via `BatchCommandProcessor(...)`. Uses `sqlcmd.exe` from ODBC tools path.
|
|
|
|
### `MigrationForm.GetSqlServerLocalDBPath()` *(static)*
|
|
**Access:** `private static`
|
|
**Behavior:** Reads the Windows registry to find the highest installed SQL Server LocalDB version and returns the path to its tools directory.
|
|
|
|
### `MigrationForm.OutputHandler(...)` *(static)*
|
|
**Access:** `private static`
|
|
**Behavior:** Appends asynchronous output from a `Process` to a static `StringBuilder` (`sb`).
|
|
|
|
### `MigrationForm.SqlCommandProcessor(...)` *(static)*
|
|
**Access:** `public static`
|
|
**Behavior:** Executes a command-line process (e.g., `sqllocaldb.exe` or batch file), captures output via `OutputHandler`, and returns accumulated output as a string.
|
|
|
|
### `MigrationForm.BatchCommandProcessor(...)` *(static)*
|
|
**Access:** `public static`
|
|
**Behavior:** Executes a batch file with arguments (e.g., database attach script), captures output, and returns accumulated output.
|
|
|
|
> **Note:** The following types are used but *not defined* in the provided source:
|
|
> - `DbOperations` (class with static `Connection`, `_usingCentralizedDB`, `_usingMSSQL`, `CURRENT_DB_VERSION`, `GetSQLCommand(...)`, `DbVersions`, `DbVersionFields`)
|
|
> - `DbOperationsEnum.StoredProcedure`
|
|
> - `MigrationResult` (enum with at least `OK`, `ExceptionThrown`, `WarningAllowStreamingModesWasNotMigrated`)
|
|
> - `Settings.Default` (properties: `LocalDbDataPROInstance`, `StopDataProInstance`, `DeleteDataProInstance`, `CreateDataProInstance`, `StartDataProInstance`, `LocalDbFolder`, `Mdf`, `LogLdf`, `DataPRO`, `ISO`, `AttachDBsbat`, `RegistrySoftwareMicrosoftMicrosoftSQLServerLocalDBInstalledVersions`, `InstanceAPIPath`, `SqlUserInstanceDll`, `LocalDB`, `Tools`, `SqlLocalDBExe`, `SqlServerLocalDbNotInstalled`, `SameVersionDatabase`, `CurrentVersionGreater`, `DatabaseMigrationSucceeded`, `DatabaseMigrationFailed`, `ActionRequired`, `Warning`, `WarningAllowStreamingModesWasNotMigrated`, `Db`)
|
|
> - `DTS.Common.Storage`, `DTS.Common.Enums`, `DTS.Common.Utils.Database` namespaces
|
|
|
|
## 3. Invariants
|
|
|
|
- `_desiredDatabaseVersion` is always set to the current value of `numericUpDownDesiredVersion` via the `ValueChanged` event handler.
|
|
- `numericUpDownDesiredVersion` is constrained to `[61, DbOperations.CURRENT_DB_VERSION]` at form load.
|
|
- Database backup is *always* attempted before migration (even if `CopyDatabaseFile` does not validate `.ldf` copy success).
|
|
- `GetDatabaseVersion` returns `0` if no version can be determined (e.g., stored procedure fails or no versions found).
|
|
- LocalDB instance setup (`InstallDatabase`) is only triggered if `localSQLLocalDbDataExists` is true *and* `GetDatabaseVersion` is called.
|
|
- `DbOperations.Connection.Server` is hardcoded to `Settings.Default.LocalDbDataPROInstance` in `InstallDatabase`.
|
|
- `DbOperations.Connection.DBName` is hardcoded to `"DataPRO"` in `GetDatabaseVersion`.
|
|
- `DbOperations.Connection.UpgradeVersionsIfNeeded(...)` is called with fixed string arguments: `"DataPRO"`, `"previousdir"`, `"targetdir"`, `"DataPRO.exe"`, `"applicationSettings"` — no dynamic configuration is used.
|
|
|
|
## 4. Dependencies
|
|
|
|
### External Dependencies (Inferred from Imports/Usings):
|
|
- `System.Windows.Forms` (UI framework)
|
|
- `System.Data.SqlClient` (SQL Server client)
|
|
- `System.Diagnostics` (process execution)
|
|
- `System.IO` (file operations)
|
|
- `Microsoft.Win32` (registry access)
|
|
- `DTS.Common.Storage` (likely contains `DbOperations` and related types)
|
|
- `DTS.Common.Enums` (likely contains `DbOperationsEnum.StoredProcedure`, `MigrationResult`, `STARTUP_ERRORS`)
|
|
- `DTS.Common.Utils.Database` (contains `GetODBCToolsPath(...)`)
|
|
|
|
### Internal Dependencies (Inferred from Usage):
|
|
- `DatabaseMigrator.Properties.Settings.Default` — provides configuration strings (e.g., instance names, file extensions, registry keys, messages).
|
|
- `DbOperations.Connection` — central database access object (must expose `Server`, `DBName`, `DbVersion`, `UpgradeVersionsIfNeeded(...)`, `GetSQLCommand(...)`, and static fields like `_usingMSSQL`, `_usingCentralizedDB`, `_usingNTLMAuthentication`).
|
|
- `DbOperationsEnum.StoredProcedure` — must include `sp_DbVersionGet`.
|
|
- `DbOperations.DbVersions` — must contain `DbVersionFields.Version`.
|
|
- `DTS.Common.Utils.Database.GetODBCToolsPath(...)` — returns path to `sqlcmd.exe`.
|
|
|
|
### What Depends on This Module:
|
|
- The main entry point (`MigrateDatabase.Main`) is invoked as a standalone executable (likely triggered by the main DataPRO installer or updater).
|
|
- No other modules in this codebase reference `MigrationForm` — it is self-contained.
|
|
|
|
## 5. Gotchas
|
|
|
|
- **Hardcoded Migration Arguments**: `DbOperations.Connection.UpgradeVersionsIfNeeded(...)` is called with fixed string parameters (`"previousdir"`, `"targetdir"`, etc.) that do not appear to be derived from user input or configuration. This may cause migration to fail if those strings are not meaningful to the underlying upgrade logic.
|
|
- **Silent `.ldf` Copy Failure**: `CopyDatabaseFile` copies the `.mdf` file first and returns `true` if that succeeds, but does *not* check success of the `.ldf` copy — potentially leaving the backup incomplete.
|
|
- **`GetDatabaseVersion` Ignores `usingLocalDatabase` Parameter**: The parameter is always `true` in practice (hardcoded in `buttonOK_Click` and `MigrationForm_Load`), and the `else` branch for centralized DB is commented out.
|
|
- **SQLite Support Inactive**: `localSQLiteDataExists` is set but never used — the SQLite fallback path in `GetDatabaseVersion` is commented out.
|
|
- **Registry Assumptions**: `GetSqlServerLocalDBPath` assumes LocalDB is installed in a specific registry path and uses hardcoded suffixes (`Settings.Default.LocalDB`, `SqlUserInstanceDll`, `InstanceAPIPath`, `Tools`). Failure to match these will cause `ProcessSqlLocalDbCommand` to fail.
|
|
- **No Validation of Desired Version**: User can select any version in the `NumericUpDown`, but `DbOperations.Connection.UpgradeVersionsIfNeeded(...)` may not support downgrades or arbitrary version jumps — behavior is unknown without its source.
|
|
- **UI Blocking**: All migration logic runs on the UI thread (synchronous `Process.WaitForExit()` calls), which may cause the form to freeze during long operations.
|
|
- **Hardcoded Database Names**: `"DataPRO"` and `"ISO"` are hardcoded in multiple places (`InstallDatabase`, `CopyLocalDB`, `LocalDataExists`). No support for custom database names.
|
|
- **`SetStatus` Parameter Unused**: The `output` parameter in `SetStatus(string status, bool output = false)` is never used.
|
|
- **`_testIDTimestamp` Format Ambiguity**: Backup filename timestamp uses space (`" {0:00}_{1:00}"`) which may cause issues on some filesystems (e.g., network shares with strict naming rules). |