Files
DP44/DataPRO/Modules/Database/DatabaseMigrator/MigrationForm.cs

499 lines
23 KiB
C#
Raw Normal View History

2026-04-17 14:55:32 -04:00
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using DatabaseMigrator.Properties;
using DTS.Common.Storage;
using Microsoft.Win32;
using DTS.Common.Enums;
namespace DatabaseMigrator
{
public partial class MigrationForm : Form
{
public MigrationForm(string targetDir)
{
InitializeComponent();
_targetDir = targetDir;
}
private readonly string _targetDir;
private int _desiredDatabaseVersion;
private bool localDataExists = false;
private bool localSQLiteDataExists = false;
private bool localSQLLocalDbDataExists = false;
private void buttonOK_Click(object sender, EventArgs e)
{
SetMigrationStatus("Querying database version...");
var currentDatabaseVersion = GetDatabaseVersion(true); //fix this rbLocal.Checked);
if (currentDatabaseVersion == _desiredDatabaseVersion)
{
MessageBox.Show(string.Format(Settings.Default.SameVersionDatabase, currentDatabaseVersion), Settings.Default.ActionRequired, MessageBoxButtons.OK,
MessageBoxIcon.Warning, MessageBoxDefaultButton.Button1, MessageBoxOptions.DefaultDesktopOnly);
}
else if (currentDatabaseVersion > _desiredDatabaseVersion)
{
MessageBox.Show(string.Format(Settings.Default.CurrentVersionGreater, currentDatabaseVersion), Settings.Default.ActionRequired, MessageBoxButtons.OK,
MessageBoxIcon.Warning, MessageBoxDefaultButton.Button1, MessageBoxOptions.DefaultDesktopOnly);
}
else
{
SetMigrationStatus("Creating a backup database prior to migration...");
//Make a backup copy
CopyLocalDB();
DbOperations.Connection.DbVersion = currentDatabaseVersion;
//Migrate the database
SetMigrationStatus("Migrating database from verion " + currentDatabaseVersion + " to " + _desiredDatabaseVersion + "...");
try
{
MigrationResult result = DbOperations.Connection.UpgradeVersionsIfNeeded(_desiredDatabaseVersion, SetStatus, "DataPRO", "previousdir", "targetdir", "DataPRO.exe", "applicationSettings" /*fix this*/); //handle exceptions and display error
if (result != MigrationResult.OK)
{
ConvertResultAndDisplay(result);
}
MessageBox.Show(string.Format(Settings.Default.DatabaseMigrationSucceeded, currentDatabaseVersion, _desiredDatabaseVersion), Settings.Default.ActionRequired, MessageBoxButtons.OK,
MessageBoxIcon.Warning, MessageBoxDefaultButton.Button1, MessageBoxOptions.DefaultDesktopOnly);
}
catch (Exception)
{
MessageBox.Show(string.Format(Settings.Default.DatabaseMigrationFailed, Environment.NewLine + Environment.NewLine), Settings.Default.ActionRequired, MessageBoxButtons.OK,
MessageBoxIcon.Warning, MessageBoxDefaultButton.Button1, MessageBoxOptions.DefaultDesktopOnly);
}
}
Close();
}
private void ConvertResultAndDisplay(MigrationResult result)
{
string stringResult = ConvertMigrationResultToSetting(result);
MessageBox.Show(stringResult, Settings.Default.ActionRequired, MessageBoxButtons.OK,
MessageBoxIcon.Warning, MessageBoxDefaultButton.Button1, MessageBoxOptions.DefaultDesktopOnly);
}
private string ConvertMigrationResultToSetting(MigrationResult result)
{
var stringResult = string.Empty;
switch (result)
{
case MigrationResult.OK:
break;
case MigrationResult.ExceptionThrown:
break;
case MigrationResult.WarningAllowStreamingModesWasNotMigrated:
stringResult = string.Format(Settings.Default.WarningAllowStreamingModesWasNotMigrated, Environment.NewLine, Environment.NewLine);
break;
}
return stringResult;
}
private void buttonCancel_Click(object sender, EventArgs e)
{
Close();
}
private string InstallDatabase()
{
DbOperations._usingCentralizedDB = false;
DbOperations._usingMSSQL = true;
DbOperations.Connection.Server = Settings.Default.LocalDbDataPROInstance;
DbOperations._usingNTLMAuthentication = true;
var resultString = ProcessSqlLocalDbCommand(Settings.Default.StopDataProInstance);
if (resultString.Length != 0)
{
MessageBox.Show(resultString, Settings.Default.Warning, MessageBoxButtons.OK);
//Environment.Exit((int)STARTUP_ERRORS.ISO_DB_NOT_ATTACHED);
}
resultString = ProcessSqlLocalDbCommand(Settings.Default.DeleteDataProInstance);
if (resultString.Length != 0)
{
MessageBox.Show(resultString, Settings.Default.Warning, MessageBoxButtons.OK);
//Environment.Exit((int)STARTUP_ERRORS.ISO_DB_NOT_ATTACHED);
}
resultString = ProcessSqlLocalDbCommand(Settings.Default.CreateDataProInstance);
if (resultString.Length != 0)
{
MessageBox.Show(resultString, Settings.Default.Warning, MessageBoxButtons.OK);
//Environment.Exit((int)STARTUP_ERRORS.ISO_DB_NOT_ATTACHED);
}
resultString = ProcessSqlLocalDbCommand(Settings.Default.StartDataProInstance);
if (resultString.Length != 0)
{
MessageBox.Show(resultString, Settings.Default.Warning, MessageBoxButtons.OK);
//Environment.Exit((int)STARTUP_ERRORS.ISO_DB_NOT_ATTACHED);
}
//Attach the DataPRO database
var dbFileName = Path.Combine(_targetDir, Settings.Default.LocalDbFolder, DbOperations.Connection.DBName) + ".mdf";
var logFileName = Path.Combine(_targetDir, Settings.Default.LocalDbFolder, DbOperations.Connection.DBName) + "_log.ldf";
resultString = AttachDatabase(_targetDir, Settings.Default.DataPRO, dbFileName, logFileName);
if (resultString.Length != 0)
{
MessageBox.Show(resultString, Settings.Default.Warning, MessageBoxButtons.OK);
//Environment.Exit((int)STARTUP_ERRORS.ISO_DB_NOT_ATTACHED);
}
//Attach the ISO database
dbFileName = Path.Combine(_targetDir, Settings.Default.LocalDbFolder, Settings.Default.ISO) + ".mdf";
logFileName = Path.Combine(_targetDir, Settings.Default.LocalDbFolder, Settings.Default.ISO) + "_log.ldf";
resultString = AttachDatabase(_targetDir, Settings.Default.ISO, dbFileName, logFileName);
if (resultString.Length != 0)
{
MessageBox.Show(resultString, Settings.Default.Warning, MessageBoxButtons.OK);
//Environment.Exit((int)STARTUP_ERRORS.ISO_DB_NOT_ATTACHED);
}
return resultString;
}
private void SetMigrationStatus(string migrationStatus)
{
//Remove the previous status
SetStatus(string.Empty);
MigrationStatusLabel.Text = migrationStatus;
MigrationStatusLabel.Refresh();
}
private void SetStatus(string status, bool output = false)
{
statusTextLabel.Text = status;
statusTextLabel.Refresh();
}
/// <summary>
/// Builds the path to the database and database log files and calls CopyDatabaseFile for each.
/// </summary>
private bool CopyLocalDB()
{
var dbFileName = Path.Combine(_targetDir, Settings.Default.LocalDbFolder, "DataPRO" /*tbDBName.Text.Trim()*/ + Settings.Default.Mdf);
var dbFileLogName = Path.Combine(_targetDir, Settings.Default.LocalDbFolder, "DataPRO" /*tbDBName.Text.Trim()*/ + Settings.Default.LogLdf);
//Copy .mdf file
if (CopyDatabaseFile(Settings.Default.Mdf, dbFileName))
{
//Copy .ldf file
CopyDatabaseFile(Settings.Default.LogLdf, dbFileLogName);
return true;
}
return false;
}
private bool CopyDatabaseFile(string extension, string destFileName)
{
//The database file that is to be copied was attached to (localdb)\DataPROInstance, so detach it so it can be copied
var resultString = ProcessSqlLocalDbCommand(Settings.Default.StopDataProInstance);
if (resultString.Length != 0)
{
MessageBox.Show(resultString, Settings.Default.Warning, MessageBoxButtons.OK);
//Environment.Exit((int)STARTUP_ERRORS.ISO_DB_NOT_ATTACHED);
}
//var sourceFileName = string.Empty;
//sourceFileName = //cbCopyDataFromPrevious.Checked ?
// Path.Combine(_targetDir, Settings.Default.LocalDbFolder, "DataPRO" /*tbDBName.Text.Trim()*/ + extension); //:
//Path.Combine(_targetDir, Settings.Default.LocalDbFolder, Settings.Default.DataPRO + extension);
//if (File.Exists(destFileName))
//{
//Back it up
var _testIDTimestamp = string.Format("{0:0000}_{1:00}_{2:00} {3:00}_{4:00}", DateTime.Now.Year,
DateTime.Now.Month, DateTime.Now.Day, DateTime.Now.Hour, DateTime.Now.Minute);
var temp = destFileName.Replace(extension, "_" + _testIDTimestamp + extension);
File.Copy(destFileName, temp, true); //Don't worry about overwriting a db with this timestamp
//}
//try
//{
// File.Copy(sourceFileName, destFileName, true);
// //log.WriteEntry(sourceFileName + " was copied as " + destFileName);
//}
//catch (Exception ex)
//{
// MessageBox.Show("Previous database was not copied: " + ex.Message);
// return false;
//}
return true;
}
private int GetDatabaseVersion(bool usingLocalDatabase)
{
var oldVersion = 0;
try
{
DbOperations.Connection.DBName = "DataPRO"; //fix this tbDBName.Text;
if (true) //fix this usingLocalDatabase)
{
//log.WriteEntry("Using local database");
if (localSQLLocalDbDataExists)
{
//log.WriteEntry("Local SQLLocalDb database exists in previous install");
var resultString = InstallDatabase();
if (resultString.Length != 0)
{
MessageBox.Show(resultString, Settings.Default.Warning,
MessageBoxButtons.OK);
//Environment.Exit((int)STARTUP_ERRORS.ISO_DB_NOT_ATTACHED);
}
}
//else if (localSQLiteDataExists)
//{
// log.WriteEntry("Local SQLite database exists in previous install");
// DbOperations._usingMSSQL = false;
// oldVersion = UsePreviousDatabaseStructure(true);
// return oldVersion;
//}
else
{
//log.WriteEntry("No local database exists in previous install");
}
}
//else
//{
// log.WriteEntry("Using centralized database");
// DbOperations._usingMSSQL = true;
// DbOperations.Connection.Server = tbDBHostname.Text;
// DbOperations._usingNTLMAuthentication = cbUseNTLMAuthentication.Checked;
// DbOperations.Connection.Username = tbDBUser.Text;
// DbOperations.Connection.Password = tbDBPassword.Text;
// }
//First try the most recent database structure
using (var cmd = DbOperations.GetSQLCommand(true))
{
try
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandText = DbOperationsEnum.StoredProcedure.sp_DbVersionGet.ToString();
cmd.Parameters.Add(new SqlParameter("@Version", SqlDbType.Int) { Value = null });
var reader = cmd.ExecuteReader();
var dbVersionsList = new List<int>();
while (reader.Read())
{
var version = Convert.ToInt32(reader[DbOperations.DbVersions.DbVersionFields.Version.ToString()]);
dbVersionsList.Add(version);
}
reader.Close();
oldVersion = dbVersionsList.Max();
//log.WriteEntry("Result of using stored procedure sp_DbVersionGet is " + oldVersion);
if (oldVersion > 0)
{
return oldVersion;
}
}
finally
{
cmd.Connection.Dispose();
}
}
}
catch (Exception)
{
//log.WriteEntry("Exception while getting previous database version: " + ex.Message);
}
return 0; //fix thisUsePreviousDatabaseStructure(usingLocalDatabase);
}
/// <summary>
/// Get the path to the latest version of SQL Server Express LocalDB
/// installed, and run the command passed in.
/// </summary>
/// <param name="command"></param>
/// <returns></returns>
private static string ProcessSqlLocalDbCommand(string command)
{
//SQL Server Express LocalDB 2014 is a Prerequisite of the DataPRO Installer,
//so it should be there unless it has been subsequently uninstalled.
var localDbPath = GetSqlServerLocalDBPath();
if (localDbPath == string.Empty)
{
//SQL Server LocalDb is not installed so display error and go away
return Settings.Default.SqlServerLocalDbNotInstalled;
}
var sqlLocalDbExeFileName = localDbPath + Settings.Default.SqlLocalDBExe;
return SqlCommandProcessor(sqlLocalDbExeFileName, command);
}
private static string AttachDatabase(string targetDir, string dbName, string sqlDbFileName, string sqlLogFileName)
{
const string SqlCmdExe = "sqlcmd.exe";
var oDBCToolsPath = DTS.Common.Utils.Database.GetODBCToolsPath(null);
var fullSqlcmdPath = Path.Combine(oDBCToolsPath, SqlCmdExe); //e.g. $"\"C:\\Program Files\\Microsoft SQL Server\\Client SDK\\ODBC\\110\\Tools\\Binn\\sqlcmd.exe\""
//var batchFileName = Path.Combine(targetDir, Settings.Default.ScriptsFolder, Settings.Default.AttachDBsbat);
var batchFileName = Settings.Default.AttachDBsbat;
return BatchCommandProcessor(batchFileName, dbName, sqlDbFileName, sqlLogFileName, fullSqlcmdPath);
}
private static string GetSqlServerLocalDBPath()
{
var highestVersionInstalledPath = string.Empty;
var rk = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64);
var sk1 = rk.OpenSubKey(Settings.Default.RegistrySoftwareMicrosoftMicrosoftSQLServerLocalDBInstalledVersions);
if (sk1 == null) return string.Empty;
var maxProductVersion = 0.0;
foreach (var productSubKeyName in sk1.GetSubKeyNames())
{
var thisVersion = -1D;
if (!double.TryParse(productSubKeyName, out thisVersion)) continue;
if (thisVersion < maxProductVersion) continue;
maxProductVersion = thisVersion;
var newKey = sk1.OpenSubKey(productSubKeyName);
if (newKey == null) continue;
var val = newKey.GetValue(Settings.Default.InstanceAPIPath, -1, RegistryValueOptions.None).ToString();
if ((val == "-1") || (!val.EndsWith(Settings.Default.SqlUserInstanceDll))) continue;
highestVersionInstalledPath = val.Substring(0, val.Length - Settings.Default.SqlUserInstanceDll.Length);
}
return highestVersionInstalledPath.Replace(Settings.Default.LocalDB, Settings.Default.Tools);
}
private static readonly StringBuilder sb = new StringBuilder();
static void OutputHandler(object sendingProcess, DataReceivedEventArgs outLine)
{
if (outLine.Data != null)
{
if (string.IsNullOrWhiteSpace(outLine.Data))
{
sb.Append("\r\n");
}
sb.Append(outLine.Data);
}
}
public static string SqlCommandProcessor(string sqlLocalDbExeFileName, string command)
{
var resultString = string.Empty;
sb.Clear();
var process = new Process
{
StartInfo =
{
FileName = sqlLocalDbExeFileName,
Arguments = command,
LoadUserProfile = true,
UseShellExecute = false,
RedirectStandardOutput = true,
RedirectStandardError = true,
CreateNoWindow = true
}
};
//* Set ONLY ONE handler here.
process.OutputDataReceived += new DataReceivedEventHandler(OutputHandler);
//* Start process
process.Start();
//* Read one element asynchronously
process.BeginErrorReadLine();
//* Read the other one synchronously
var output = process.StandardOutput.ReadToEnd();
Console.WriteLine(output);
//APILogger.Log("Result of " + command + " command is: " + output);
process.WaitForExit();
if (sb.Length > 0)
{
resultString = sb.ToString();
}
return resultString;
}
public static string BatchCommandProcessor(string batchFileName, string dbName, string sqlDbFileName, string sqlLogFileName,
string fullSqlcmdPath)
{
var resultString = string.Empty;
sb.Clear();
var process = new Process
{
StartInfo =
{
FileName = batchFileName,
Arguments = dbName + " " + "\"" + sqlDbFileName + "\"" + " " + "\"" + sqlLogFileName + "\"" + " " + "\"" + fullSqlcmdPath + "\"",
LoadUserProfile = true,
UseShellExecute = false,
RedirectStandardOutput = true,
RedirectStandardError = true,
CreateNoWindow = true
}
};
//* Set ONLY ONE handler here.
process.OutputDataReceived += new DataReceivedEventHandler(OutputHandler);
//* Start process
process.Start();
//* Read one element asynchronously
process.BeginErrorReadLine();
//* Read the other one synchronously
var output = process.StandardOutput.ReadToEnd();
Console.WriteLine(output);
//APILogger.Log("Result of attach " + dbName + " using " + sqlDbFileName + " and " + sqlLogFileName + " is:");
//APILogger.Log(output);
process.WaitForExit();
if (sb.Length > 0)
{
resultString = sb.ToString();
}
return resultString;
}
private bool LocalDataExists()
{
//if (!PreviousVersionInstalled())
//{
// return false;
//}
//Check for "DataPRO.mdf" (SqlLocalDb in 1.5 or later) in previously-installed folder
var sourceFileName = Path.Combine(_targetDir, Settings.Default.LocalDbFolder, "DataPRO" /*tbDBName.Text*/ + Settings.Default.Mdf);
if (File.Exists(sourceFileName))
{
localSQLLocalDbDataExists = true;
return true;
}
else
{
localSQLLocalDbDataExists = false;
//Check for "datapro.db" (SQLite file in 1.4 or earlier) in previously-installed folder
sourceFileName = Path.Combine(_targetDir, Settings.Default.LocalDbFolder, "DataPRO" /*tbDBName.Text*/ + Settings.Default.Db);
if (File.Exists(sourceFileName))
{
localSQLiteDataExists = true;
return true;
}
else
{
localSQLiteDataExists = false;
return false;
}
}
}
private void MigrationForm_Load(object sender, EventArgs e)
{
numericUpDownDesiredVersion.Minimum = 61;
numericUpDownDesiredVersion.Maximum = DbOperations.CURRENT_DB_VERSION;
numericUpDownDesiredVersion.Value = DbOperations.CURRENT_DB_VERSION;
localDataExists = LocalDataExists();
if (localSQLLocalDbDataExists)
{
TbDatabasePath.Text = Path.Combine(_targetDir, Settings.Default.LocalDbFolder, "DataPRO" /*tbDBName.Text*/ + Settings.Default.Mdf);
}
}
private void numericUpDownDesiredVersion_ValueChanged(object sender, EventArgs e)
{
_desiredDatabaseVersion = Convert.ToInt32(numericUpDownDesiredVersion.Value);
}
}
}