DB operations now occur w/in transactions, added Open DB Form to tester

This commit is contained in:
2025-09-01 08:27:18 -05:00
parent b0cb847d23
commit 12386fe11d
10 changed files with 598 additions and 175 deletions

View File

@@ -42,6 +42,7 @@
<Reference Include="DevExpress.Utils.v23.2, Version=23.2.3.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a, processorArchitecture=MSIL" /> <Reference Include="DevExpress.Utils.v23.2, Version=23.2.3.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a, processorArchitecture=MSIL" />
<Reference Include="DevExpress.XtraBars.v23.2, Version=23.2.3.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a, processorArchitecture=MSIL" /> <Reference Include="DevExpress.XtraBars.v23.2, Version=23.2.3.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a, processorArchitecture=MSIL" />
<Reference Include="DevExpress.XtraEditors.v23.2, Version=23.2.3.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a, processorArchitecture=MSIL" /> <Reference Include="DevExpress.XtraEditors.v23.2, Version=23.2.3.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a, processorArchitecture=MSIL" />
<Reference Include="DevExpress.XtraLayout.v23.2, Version=23.2.3.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a, processorArchitecture=MSIL" />
<Reference Include="System" /> <Reference Include="System" />
<Reference Include="System.Core" /> <Reference Include="System.Core" />
<Reference Include="System.Data.SQLite, Version=1.0.119.0, Culture=neutral, PublicKeyToken=db937bc2d44ff139, processorArchitecture=MSIL"> <Reference Include="System.Data.SQLite, Version=1.0.119.0, Culture=neutral, PublicKeyToken=db937bc2d44ff139, processorArchitecture=MSIL">
@@ -64,11 +65,20 @@
<Compile Include="Forms\MainForm.Designer.cs"> <Compile Include="Forms\MainForm.Designer.cs">
<DependentUpon>MainForm.cs</DependentUpon> <DependentUpon>MainForm.cs</DependentUpon>
</Compile> </Compile>
<Compile Include="Forms\OpenForm.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="Forms\OpenForm.Designer.cs">
<DependentUpon>OpenForm.cs</DependentUpon>
</Compile>
<Compile Include="Program.cs" /> <Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
<EmbeddedResource Include="Forms\MainForm.resx"> <EmbeddedResource Include="Forms\MainForm.resx">
<DependentUpon>MainForm.cs</DependentUpon> <DependentUpon>MainForm.cs</DependentUpon>
</EmbeddedResource> </EmbeddedResource>
<EmbeddedResource Include="Forms\OpenForm.resx">
<DependentUpon>OpenForm.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Properties\licenses.licx" /> <EmbeddedResource Include="Properties\licenses.licx" />
<EmbeddedResource Include="Properties\Resources.resx"> <EmbeddedResource Include="Properties\Resources.resx">
<Generator>ResXFileCodeGenerator</Generator> <Generator>ResXFileCodeGenerator</Generator>

View File

@@ -30,24 +30,26 @@
DevExpress.XtraEditors.Controls.EditorButtonImageOptions editorButtonImageOptions2 = new DevExpress.XtraEditors.Controls.EditorButtonImageOptions(); DevExpress.XtraEditors.Controls.EditorButtonImageOptions editorButtonImageOptions2 = new DevExpress.XtraEditors.Controls.EditorButtonImageOptions();
DevExpress.Utils.SerializableAppearanceObject serializableAppearanceObject2 = new DevExpress.Utils.SerializableAppearanceObject(); DevExpress.Utils.SerializableAppearanceObject serializableAppearanceObject2 = new DevExpress.Utils.SerializableAppearanceObject();
this.barManager1 = new DevExpress.XtraBars.BarManager(this.components); this.barManager1 = new DevExpress.XtraBars.BarManager(this.components);
this.bar1 = new DevExpress.XtraBars.Bar();
this.bbiDelta = new DevExpress.XtraBars.BarButtonItem();
this.bbiMigrations = new DevExpress.XtraBars.BarButtonItem();
this.bbiApplyBoth = new DevExpress.XtraBars.BarButtonItem();
this.bar2 = new DevExpress.XtraBars.Bar();
this.bar3 = new DevExpress.XtraBars.Bar();
this.barDockControlTop = new DevExpress.XtraBars.BarDockControl(); this.barDockControlTop = new DevExpress.XtraBars.BarDockControl();
this.barDockControlBottom = new DevExpress.XtraBars.BarDockControl(); this.barDockControlBottom = new DevExpress.XtraBars.BarDockControl();
this.barDockControlLeft = new DevExpress.XtraBars.BarDockControl(); this.barDockControlLeft = new DevExpress.XtraBars.BarDockControl();
this.barDockControlRight = new DevExpress.XtraBars.BarDockControl(); this.barDockControlRight = new DevExpress.XtraBars.BarDockControl();
this.bar1 = new DevExpress.XtraBars.Bar();
this.bar2 = new DevExpress.XtraBars.Bar();
this.bar3 = new DevExpress.XtraBars.Bar();
this.bbiDelta = new DevExpress.XtraBars.BarButtonItem();
this.bbiMigrations = new DevExpress.XtraBars.BarButtonItem();
this.bbiApplyBoth = new DevExpress.XtraBars.BarButtonItem();
this.XtraTabControl1 = new DevExpress.XtraTab.XtraTabControl(); this.XtraTabControl1 = new DevExpress.XtraTab.XtraTabControl();
this.xtraTabPage1 = new DevExpress.XtraTab.XtraTabPage(); this.xtraTabPage1 = new DevExpress.XtraTab.XtraTabPage();
this.xtraTabPage2 = new DevExpress.XtraTab.XtraTabPage();
this.xtraTabPage3 = new DevExpress.XtraTab.XtraTabPage();
this.xtraTabPage4 = new DevExpress.XtraTab.XtraTabPage();
this.db1Sql = new System.Windows.Forms.RichTextBox(); this.db1Sql = new System.Windows.Forms.RichTextBox();
this.xtraTabPage2 = new DevExpress.XtraTab.XtraTabPage();
this.db2Sql = new System.Windows.Forms.RichTextBox(); this.db2Sql = new System.Windows.Forms.RichTextBox();
this.xtraTabPage3 = new DevExpress.XtraTab.XtraTabPage();
this.deltaSql = new System.Windows.Forms.RichTextBox(); this.deltaSql = new System.Windows.Forms.RichTextBox();
this.xtraTabPage4 = new DevExpress.XtraTab.XtraTabPage();
this.btsRemoveUnusedTables = new DevExpress.XtraBars.BarToggleSwitchItem();
this.btsRemoveUnusedColumns = new DevExpress.XtraBars.BarToggleSwitchItem();
((System.ComponentModel.ISupportInitialize)(this.barManager1)).BeginInit(); ((System.ComponentModel.ISupportInitialize)(this.barManager1)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.XtraTabControl1)).BeginInit(); ((System.ComponentModel.ISupportInitialize)(this.XtraTabControl1)).BeginInit();
this.XtraTabControl1.SuspendLayout(); this.XtraTabControl1.SuspendLayout();
@@ -70,11 +72,70 @@
this.barManager1.Items.AddRange(new DevExpress.XtraBars.BarItem[] { this.barManager1.Items.AddRange(new DevExpress.XtraBars.BarItem[] {
this.bbiDelta, this.bbiDelta,
this.bbiMigrations, this.bbiMigrations,
this.bbiApplyBoth}); this.bbiApplyBoth,
this.btsRemoveUnusedTables,
this.btsRemoveUnusedColumns});
this.barManager1.MainMenu = this.bar2; this.barManager1.MainMenu = this.bar2;
this.barManager1.MaxItemId = 3; this.barManager1.MaxItemId = 6;
this.barManager1.StatusBar = this.bar3; this.barManager1.StatusBar = this.bar3;
// //
// bar1
//
this.bar1.BarName = "Tools";
this.bar1.DockCol = 0;
this.bar1.DockRow = 1;
this.bar1.DockStyle = DevExpress.XtraBars.BarDockStyle.Top;
this.bar1.LinksPersistInfo.AddRange(new DevExpress.XtraBars.LinkPersistInfo[] {
new DevExpress.XtraBars.LinkPersistInfo(this.bbiDelta),
new DevExpress.XtraBars.LinkPersistInfo(this.bbiMigrations),
new DevExpress.XtraBars.LinkPersistInfo(this.bbiApplyBoth),
new DevExpress.XtraBars.LinkPersistInfo(this.btsRemoveUnusedTables, true),
new DevExpress.XtraBars.LinkPersistInfo(this.btsRemoveUnusedColumns)});
this.bar1.Text = "Tools";
//
// bbiDelta
//
this.bbiDelta.Caption = "Generate Delta";
this.bbiDelta.Id = 0;
this.bbiDelta.Name = "bbiDelta";
this.bbiDelta.ItemClick += new DevExpress.XtraBars.ItemClickEventHandler(this.ToolbarItemClicked);
//
// bbiMigrations
//
this.bbiMigrations.Caption = "Get Migration List";
this.bbiMigrations.Id = 1;
this.bbiMigrations.Name = "bbiMigrations";
this.bbiMigrations.ItemClick += new DevExpress.XtraBars.ItemClickEventHandler(this.ToolbarItemClicked);
//
// bbiApplyBoth
//
this.bbiApplyBoth.Caption = "Apply Delta && Migrations";
this.bbiApplyBoth.Id = 2;
this.bbiApplyBoth.Name = "bbiApplyBoth";
this.bbiApplyBoth.ItemClick += new DevExpress.XtraBars.ItemClickEventHandler(this.ToolbarItemClicked);
//
// bar2
//
this.bar2.BarName = "Main menu";
this.bar2.DockCol = 0;
this.bar2.DockRow = 0;
this.bar2.DockStyle = DevExpress.XtraBars.BarDockStyle.Top;
this.bar2.OptionsBar.MultiLine = true;
this.bar2.OptionsBar.UseWholeRow = true;
this.bar2.Text = "Main menu";
//
// bar3
//
this.bar3.BarName = "Status bar";
this.bar3.CanDockStyle = DevExpress.XtraBars.BarCanDockStyle.Bottom;
this.bar3.DockCol = 0;
this.bar3.DockRow = 0;
this.bar3.DockStyle = DevExpress.XtraBars.BarDockStyle.Bottom;
this.bar3.OptionsBar.AllowQuickCustomization = false;
this.bar3.OptionsBar.DrawDragBorder = false;
this.bar3.OptionsBar.UseWholeRow = true;
this.bar3.Text = "Status bar";
//
// barDockControlTop // barDockControlTop
// //
this.barDockControlTop.CausesValidation = false; this.barDockControlTop.CausesValidation = false;
@@ -107,58 +168,6 @@
this.barDockControlRight.Manager = this.barManager1; this.barDockControlRight.Manager = this.barManager1;
this.barDockControlRight.Size = new System.Drawing.Size(0, 417); this.barDockControlRight.Size = new System.Drawing.Size(0, 417);
// //
// bar1
//
this.bar1.BarName = "Tools";
this.bar1.DockCol = 0;
this.bar1.DockStyle = DevExpress.XtraBars.BarDockStyle.Top;
this.bar1.LinksPersistInfo.AddRange(new DevExpress.XtraBars.LinkPersistInfo[] {
new DevExpress.XtraBars.LinkPersistInfo(this.bbiDelta),
new DevExpress.XtraBars.LinkPersistInfo(this.bbiMigrations),
new DevExpress.XtraBars.LinkPersistInfo(this.bbiApplyBoth)});
this.bar1.Text = "Tools";
//
// bar2
//
this.bar2.BarName = "Main menu";
this.bar2.DockCol = 0;
this.bar2.DockStyle = DevExpress.XtraBars.BarDockStyle.Top;
this.bar2.OptionsBar.MultiLine = true;
this.bar2.OptionsBar.UseWholeRow = true;
this.bar2.Text = "Main menu";
//
// bar3
//
this.bar3.BarName = "Status bar";
this.bar3.CanDockStyle = DevExpress.XtraBars.BarCanDockStyle.Bottom;
this.bar3.DockCol = 0;
this.bar3.DockStyle = DevExpress.XtraBars.BarDockStyle.Bottom;
this.bar3.OptionsBar.AllowQuickCustomization = false;
this.bar3.OptionsBar.DrawDragBorder = false;
this.bar3.OptionsBar.UseWholeRow = true;
this.bar3.Text = "Status bar";
//
// bbiDelta
//
this.bbiDelta.Caption = "Generate Delta";
this.bbiDelta.Id = 0;
this.bbiDelta.Name = "bbiDelta";
this.bbiDelta.ItemClick += new DevExpress.XtraBars.ItemClickEventHandler(this.ToolbarItemClicked);
//
// bbiMigrations
//
this.bbiMigrations.Caption = "Get Migration List";
this.bbiMigrations.Id = 1;
this.bbiMigrations.Name = "bbiMigrations";
this.bbiMigrations.ItemClick += new DevExpress.XtraBars.ItemClickEventHandler(this.ToolbarItemClicked);
//
// bbiApplyBoth
//
this.bbiApplyBoth.Caption = "Apply Delta && Migrations";
this.bbiApplyBoth.Id = 2;
this.bbiApplyBoth.Name = "bbiApplyBoth";
this.bbiApplyBoth.ItemClick += new DevExpress.XtraBars.ItemClickEventHandler(this.ToolbarItemClicked);
//
// XtraTabControl1 // XtraTabControl1
// //
editorButtonImageOptions1.Image = ((System.Drawing.Image)(resources.GetObject("editorButtonImageOptions1.Image"))); editorButtonImageOptions1.Image = ((System.Drawing.Image)(resources.GetObject("editorButtonImageOptions1.Image")));
@@ -186,26 +195,6 @@
this.xtraTabPage1.Size = new System.Drawing.Size(838, 375); this.xtraTabPage1.Size = new System.Drawing.Size(838, 375);
this.xtraTabPage1.Text = "Live / Production DB"; this.xtraTabPage1.Text = "Live / Production DB";
// //
// xtraTabPage2
//
this.xtraTabPage2.Controls.Add(this.db2Sql);
this.xtraTabPage2.Name = "xtraTabPage2";
this.xtraTabPage2.Size = new System.Drawing.Size(838, 392);
this.xtraTabPage2.Text = "Schema / Updated DB";
//
// xtraTabPage3
//
this.xtraTabPage3.Controls.Add(this.deltaSql);
this.xtraTabPage3.Name = "xtraTabPage3";
this.xtraTabPage3.Size = new System.Drawing.Size(838, 392);
this.xtraTabPage3.Text = "Delta SQL";
//
// xtraTabPage4
//
this.xtraTabPage4.Name = "xtraTabPage4";
this.xtraTabPage4.Size = new System.Drawing.Size(0, 0);
this.xtraTabPage4.Text = "Migrations";
//
// db1Sql // db1Sql
// //
this.db1Sql.Dock = System.Windows.Forms.DockStyle.Fill; this.db1Sql.Dock = System.Windows.Forms.DockStyle.Fill;
@@ -217,6 +206,13 @@
this.db1Sql.TabIndex = 0; this.db1Sql.TabIndex = 0;
this.db1Sql.Text = "This database is the one that is currently in use by the application. This databa" + this.db1Sql.Text = "This database is the one that is currently in use by the application. This databa" +
"se needs to be updated to fit the most recent schema."; "se needs to be updated to fit the most recent schema.";
//
// xtraTabPage2
//
this.xtraTabPage2.Controls.Add(this.db2Sql);
this.xtraTabPage2.Name = "xtraTabPage2";
this.xtraTabPage2.Size = new System.Drawing.Size(838, 375);
this.xtraTabPage2.Text = "Schema / Updated DB";
// //
// db2Sql // db2Sql
// //
@@ -225,10 +221,17 @@
this.db2Sql.Location = new System.Drawing.Point(0, 0); this.db2Sql.Location = new System.Drawing.Point(0, 0);
this.db2Sql.Name = "db2Sql"; this.db2Sql.Name = "db2Sql";
this.db2Sql.ReadOnly = true; this.db2Sql.ReadOnly = true;
this.db2Sql.Size = new System.Drawing.Size(838, 392); this.db2Sql.Size = new System.Drawing.Size(838, 375);
this.db2Sql.TabIndex = 1; this.db2Sql.TabIndex = 1;
this.db2Sql.Text = resources.GetString("db2Sql.Text"); this.db2Sql.Text = resources.GetString("db2Sql.Text");
// //
// xtraTabPage3
//
this.xtraTabPage3.Controls.Add(this.deltaSql);
this.xtraTabPage3.Name = "xtraTabPage3";
this.xtraTabPage3.Size = new System.Drawing.Size(838, 375);
this.xtraTabPage3.Text = "Delta SQL";
//
// deltaSql // deltaSql
// //
this.deltaSql.Dock = System.Windows.Forms.DockStyle.Fill; this.deltaSql.Dock = System.Windows.Forms.DockStyle.Fill;
@@ -236,10 +239,28 @@
this.deltaSql.Location = new System.Drawing.Point(0, 0); this.deltaSql.Location = new System.Drawing.Point(0, 0);
this.deltaSql.Name = "deltaSql"; this.deltaSql.Name = "deltaSql";
this.deltaSql.ReadOnly = true; this.deltaSql.ReadOnly = true;
this.deltaSql.Size = new System.Drawing.Size(838, 392); this.deltaSql.Size = new System.Drawing.Size(838, 375);
this.deltaSql.TabIndex = 1; this.deltaSql.TabIndex = 1;
this.deltaSql.Text = "This SQL script contains all of the SQL commands required to make the production " + this.deltaSql.Text = "This SQL script contains all of the SQL commands required to make the production " +
"(existing) database the same as the new template database."; "(existing) database the same as the new template database.";
//
// xtraTabPage4
//
this.xtraTabPage4.Name = "xtraTabPage4";
this.xtraTabPage4.Size = new System.Drawing.Size(838, 375);
this.xtraTabPage4.Text = "Migrations";
//
// btsRemoveUnusedTables
//
this.btsRemoveUnusedTables.Caption = "Remove Unused Tables";
this.btsRemoveUnusedTables.Id = 4;
this.btsRemoveUnusedTables.Name = "btsRemoveUnusedTables";
//
// btsRemoveUnusedColumns
//
this.btsRemoveUnusedColumns.Caption = "Remove Unused Columns";
this.btsRemoveUnusedColumns.Id = 5;
this.btsRemoveUnusedColumns.Name = "btsRemoveUnusedColumns";
// //
// MainForm // MainForm
// //
@@ -286,5 +307,7 @@
private System.Windows.Forms.RichTextBox db1Sql; private System.Windows.Forms.RichTextBox db1Sql;
private System.Windows.Forms.RichTextBox db2Sql; private System.Windows.Forms.RichTextBox db2Sql;
private System.Windows.Forms.RichTextBox deltaSql; private System.Windows.Forms.RichTextBox deltaSql;
private DevExpress.XtraBars.BarToggleSwitchItem btsRemoveUnusedTables;
private DevExpress.XtraBars.BarToggleSwitchItem btsRemoveUnusedColumns;
} }
} }

View File

@@ -5,22 +5,24 @@ using System.Windows.Forms;
namespace DbToolsTester.Forms { namespace DbToolsTester.Forms {
public partial class MainForm : DevExpress.XtraEditors.XtraForm { public partial class MainForm : DevExpress.XtraEditors.XtraForm {
public static MainForm Instance { get; private set; }
public string DatabaseName { get; set; } public string DatabaseName { get; set; }
public string Database1File { get; set; } public string Database1File { get; set; }
public string Database2File { get; set; } public string Database2File { get; set; }
public MainForm() { public MainForm() {
InitializeComponent(); InitializeComponent();
Instance = this;
} }
private void XtraTabControl1_CustomHeaderButtonClick(object sender, DevExpress.XtraTab.ViewInfo.CustomHeaderButtonEventArgs e) { private void XtraTabControl1_CustomHeaderButtonClick(object sender, DevExpress.XtraTab.ViewInfo.CustomHeaderButtonEventArgs e) {
string tag = e.Button.Tag?.ToString(); string tag = e.Button.Tag?.ToString();
if (tag == "open") { if (tag == "open") {
Database1File = getDatabaseFile("Select Original / Production Database..."); OpenForm frm = new OpenForm();
Database2File = getDatabaseFile("Select Template / New Schema Database..."); if (frm.ShowDialog(this) == DialogResult.OK) {
// Databases are set in OpenForm
DatabaseName = Path.GetFileNameWithoutExtension(Database1File); SetDatabases(frm.Db1Path, frm.Db2Path);
Text += " [ Production DB = " + Path.GetFileName(Database1File) + "; Schema DB = " + Path.GetFileName(Database2File) + " ]"; }
} else if (tag == "clear") { } else if (tag == "clear") {
Database1File = null; Database1File = null;
Database2File = null; Database2File = null;
@@ -33,6 +35,13 @@ namespace DbToolsTester.Forms {
} }
} }
public void SetDatabases(string db1File, string db2File) {
Database1File = db1File;
Database2File = db2File;
DatabaseName = Path.GetFileNameWithoutExtension(Database1File);
Text += " [ Production DB = " + Path.GetFileName(Database1File) + "; Schema DB = " + Path.GetFileName(Database2File) + " ]";
}
private string getDatabaseFile(string title = "Select Database File...") { private string getDatabaseFile(string title = "Select Database File...") {
OpenFileDialog dlg = new OpenFileDialog() { OpenFileDialog dlg = new OpenFileDialog() {
Filter = "Database Files (*.sql;*.sqlite;*.db)|*.sql;*.sqlite;*.db|SQL Files (*.sql)|*.sql|Sqlite Files (*.sqlite;*.db)|*.sqlite;*.db|Text Files (*.txt)|*.txt|All Files (*.*)|*.*", Filter = "Database Files (*.sql;*.sqlite;*.db)|*.sql;*.sqlite;*.db|SQL Files (*.sql)|*.sql|Sqlite Files (*.sqlite;*.db)|*.sqlite;*.db|Text Files (*.txt)|*.txt|All Files (*.*)|*.*",
@@ -52,9 +61,25 @@ namespace DbToolsTester.Forms {
SQLiteConnection db2 = new SQLiteConnection("Data Source=" + Database2File + ";Version=3;"); SQLiteConnection db2 = new SQLiteConnection("Data Source=" + Database2File + ";Version=3;");
Delta delta = new Delta(); Delta delta = new Delta();
deltaSql.Text = delta.BuildDelta(db1, db2, true, true); deltaSql.Text = delta.BuildDelta(db1, db2, btsRemoveUnusedTables.Checked, btsRemoveUnusedColumns.Checked);
db1Sql.Text = delta.Db1Sql; db1Sql.Text = delta.Db1Sql;
db2Sql.Text = delta.Db2Sql; db2Sql.Text = delta.Db2Sql;
} else if (e.Item.Equals(bbiApplyBoth)) {
if (string.IsNullOrEmpty(deltaSql.Text)) {
MessageBox.Show("No delta SQL to apply.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
using (var db1 = new SQLiteConnection("Data Source=" + Database1File + ";Version=3;")) {
db1.Open();
Delta delta = new Delta();
bool success = delta.ApplyDelta(db1, deltaSql.Text);
if (success) {
MessageBox.Show("Delta applied successfully.", "Success", MessageBoxButtons.OK, MessageBoxIcon.Information);
} else {
MessageBox.Show("Failed to apply delta." + (delta.LastError != null ? "\r\n\r\n" + delta.LastError.Message : ""), "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
} }
} }
} }

View File

@@ -123,88 +123,88 @@
<assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" /> <assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<data name="editorButtonImageOptions1.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64"> <data name="editorButtonImageOptions1.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value> <value>
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 rwED/gtPhKgGMZyDxQAAAABJRU5ErkJggg==
</value> </value>
</data> </data>
<data name="editorButtonImageOptions2.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64"> <data name="editorButtonImageOptions2.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value> <value>
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
</value> </value>
</data> </data>
<data name="db2Sql.Text" xml:space="preserve"> <data name="db2Sql.Text" xml:space="preserve">

178
DbToolsTester/Forms/OpenForm.Designer.cs generated Normal file
View File

@@ -0,0 +1,178 @@
namespace DbToolsTester.Forms {
partial class OpenForm {
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing) {
if (disposing && (components != null)) {
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent() {
this.layoutControl1 = new DevExpress.XtraLayout.LayoutControl();
this.Root = new DevExpress.XtraLayout.LayoutControlGroup();
this.Db1File = new DevExpress.XtraEditors.ButtonEdit();
this.layoutControlItem1 = new DevExpress.XtraLayout.LayoutControlItem();
this.emptySpaceItem1 = new DevExpress.XtraLayout.EmptySpaceItem();
this.db2File = new DevExpress.XtraEditors.ButtonEdit();
this.layoutControlItem2 = new DevExpress.XtraLayout.LayoutControlItem();
this.btnOpen = new DevExpress.XtraEditors.SimpleButton();
this.btnCancel = new DevExpress.XtraEditors.SimpleButton();
((System.ComponentModel.ISupportInitialize)(this.layoutControl1)).BeginInit();
this.layoutControl1.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.Root)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.Db1File.Properties)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.layoutControlItem1)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.emptySpaceItem1)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.db2File.Properties)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.layoutControlItem2)).BeginInit();
this.SuspendLayout();
//
// layoutControl1
//
this.layoutControl1.Controls.Add(this.db2File);
this.layoutControl1.Controls.Add(this.Db1File);
this.layoutControl1.Dock = System.Windows.Forms.DockStyle.Top;
this.layoutControl1.Location = new System.Drawing.Point(0, 0);
this.layoutControl1.Name = "layoutControl1";
this.layoutControl1.Root = this.Root;
this.layoutControl1.Size = new System.Drawing.Size(561, 167);
this.layoutControl1.TabIndex = 0;
this.layoutControl1.Text = "layoutControl1";
//
// Root
//
this.Root.EnableIndentsWithoutBorders = DevExpress.Utils.DefaultBoolean.True;
this.Root.GroupBordersVisible = false;
this.Root.Items.AddRange(new DevExpress.XtraLayout.BaseLayoutItem[] {
this.layoutControlItem1,
this.emptySpaceItem1,
this.layoutControlItem2});
this.Root.Name = "Root";
this.Root.Size = new System.Drawing.Size(561, 167);
this.Root.TextVisible = false;
//
// Db1File
//
this.Db1File.EditValue = "C:\\Users\\rlkollman\\AppData\\Local\\LEMS\\MDB6\\data.db";
this.Db1File.Location = new System.Drawing.Point(12, 28);
this.Db1File.Name = "Db1File";
this.Db1File.Properties.Buttons.AddRange(new DevExpress.XtraEditors.Controls.EditorButton[] {
new DevExpress.XtraEditors.Controls.EditorButton()});
this.Db1File.Size = new System.Drawing.Size(537, 20);
this.Db1File.StyleController = this.layoutControl1;
this.Db1File.TabIndex = 4;
this.Db1File.ButtonClick += new DevExpress.XtraEditors.Controls.ButtonPressedEventHandler(this.Db1File_ButtonClick);
//
// layoutControlItem1
//
this.layoutControlItem1.Control = this.Db1File;
this.layoutControlItem1.Location = new System.Drawing.Point(0, 0);
this.layoutControlItem1.Name = "layoutControlItem1";
this.layoutControlItem1.Size = new System.Drawing.Size(541, 40);
this.layoutControlItem1.Text = "Production Database (in-use database)";
this.layoutControlItem1.TextLocation = DevExpress.Utils.Locations.Top;
this.layoutControlItem1.TextSize = new System.Drawing.Size(188, 13);
//
// emptySpaceItem1
//
this.emptySpaceItem1.AllowHotTrack = false;
this.emptySpaceItem1.Location = new System.Drawing.Point(0, 80);
this.emptySpaceItem1.Name = "emptySpaceItem1";
this.emptySpaceItem1.Size = new System.Drawing.Size(541, 67);
this.emptySpaceItem1.TextSize = new System.Drawing.Size(0, 0);
//
// db2File
//
this.db2File.EditValue = "F:\\programming\\net\\MobileDataBrowser\\MobileDataBrowser6\\data with codelists separ" +
"ated.db";
this.db2File.Location = new System.Drawing.Point(12, 68);
this.db2File.Name = "db2File";
this.db2File.Properties.Buttons.AddRange(new DevExpress.XtraEditors.Controls.EditorButton[] {
new DevExpress.XtraEditors.Controls.EditorButton()});
this.db2File.Size = new System.Drawing.Size(537, 20);
this.db2File.StyleController = this.layoutControl1;
this.db2File.TabIndex = 5;
this.db2File.ButtonClick += new DevExpress.XtraEditors.Controls.ButtonPressedEventHandler(this.Db1File_ButtonClick);
//
// layoutControlItem2
//
this.layoutControlItem2.Control = this.db2File;
this.layoutControlItem2.Location = new System.Drawing.Point(0, 40);
this.layoutControlItem2.Name = "layoutControlItem2";
this.layoutControlItem2.Size = new System.Drawing.Size(541, 40);
this.layoutControlItem2.Text = "New / Template Database";
this.layoutControlItem2.TextLocation = DevExpress.Utils.Locations.Top;
this.layoutControlItem2.TextSize = new System.Drawing.Size(188, 13);
//
// btnOpen
//
this.btnOpen.DialogResult = System.Windows.Forms.DialogResult.OK;
this.btnOpen.Location = new System.Drawing.Point(307, 173);
this.btnOpen.Name = "btnOpen";
this.btnOpen.Size = new System.Drawing.Size(118, 43);
this.btnOpen.TabIndex = 1;
this.btnOpen.Text = "&Open";
this.btnOpen.Click += new System.EventHandler(this.btnOpen_Click);
//
// btnCancel
//
this.btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel;
this.btnCancel.Location = new System.Drawing.Point(431, 173);
this.btnCancel.Name = "btnCancel";
this.btnCancel.Size = new System.Drawing.Size(118, 43);
this.btnCancel.TabIndex = 2;
this.btnCancel.Text = "&Cancel";
//
// OpenForm
//
this.AcceptButton = this.btnOpen;
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.CancelButton = this.btnCancel;
this.ClientSize = new System.Drawing.Size(561, 233);
this.Controls.Add(this.btnCancel);
this.Controls.Add(this.btnOpen);
this.Controls.Add(this.layoutControl1);
this.Name = "OpenForm";
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
this.Text = "Open Databases ...";
((System.ComponentModel.ISupportInitialize)(this.layoutControl1)).EndInit();
this.layoutControl1.ResumeLayout(false);
((System.ComponentModel.ISupportInitialize)(this.Root)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.Db1File.Properties)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.layoutControlItem1)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.emptySpaceItem1)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.db2File.Properties)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.layoutControlItem2)).EndInit();
this.ResumeLayout(false);
}
#endregion
private DevExpress.XtraLayout.LayoutControl layoutControl1;
private DevExpress.XtraLayout.LayoutControlGroup Root;
private DevExpress.XtraEditors.ButtonEdit db2File;
private DevExpress.XtraEditors.ButtonEdit Db1File;
private DevExpress.XtraLayout.LayoutControlItem layoutControlItem1;
private DevExpress.XtraLayout.EmptySpaceItem emptySpaceItem1;
private DevExpress.XtraLayout.LayoutControlItem layoutControlItem2;
private DevExpress.XtraEditors.SimpleButton btnOpen;
private DevExpress.XtraEditors.SimpleButton btnCancel;
}
}

View File

@@ -0,0 +1,35 @@
using System;
using System.Windows.Forms;
namespace DbToolsTester.Forms {
public partial class OpenForm : DevExpress.XtraEditors.XtraForm {
public string Db1Path => Db1File.Text;
public string Db2Path => db2File.Text;
public OpenForm() {
InitializeComponent();
}
private void btnOpen_Click(object sender, EventArgs e) {
MainForm.Instance.SetDatabases(Db1File.Text, db2File.Text);
}
private void Db1File_ButtonClick(object sender, DevExpress.XtraEditors.Controls.ButtonPressedEventArgs e) {
if (e.Button.Kind == DevExpress.XtraEditors.Controls.ButtonPredefines.Ellipsis) {
OpenFileDialog dlg = new OpenFileDialog() {
Filter = "Database Files (*.sql;*.sqlite;*.db)|*.sql;*.sqlite;*.db|SQL Files (*.sql)|*.sql|Sqlite Files (*.sqlite;*.db)|*.sqlite;*.db|Text Files (*.txt)|*.txt|All Files (*.*)|*.*",
CheckFileExists = true,
Multiselect = false,
Title = "Select Database File"
};
if (dlg.ShowDialog() == DialogResult.OK) {
if (sender.Equals(Db1File)) {
Db1File.Text = dlg.FileName;
} else if (sender.Equals(db2File)) {
db2File.Text = dlg.FileName;
}
}
}
}
}
}

View File

@@ -0,0 +1,120 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

View File

@@ -1 +1,3 @@
DevExpress.XtraEditors.ButtonEdit, DevExpress.XtraEditors.v23.2, Version=23.2.3.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a
DevExpress.XtraLayout.LayoutControl, DevExpress.XtraLayout.v23.2, Version=23.2.3.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a
DevExpress.XtraBars.BarManager, DevExpress.XtraBars.v23.2, Version=23.2.3.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a DevExpress.XtraBars.BarManager, DevExpress.XtraBars.v23.2, Version=23.2.3.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a

View File

@@ -1,4 +1,5 @@
using DbTools.Model; using DbTools.Model;
using System;
using System.Data; using System.Data;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
@@ -8,6 +9,7 @@ namespace DbTools {
public class Delta { public class Delta {
public string Db1Sql { get; set; } public string Db1Sql { get; set; }
public string Db2Sql { get; set; } public string Db2Sql { get; set; }
public Exception LastError { get; private set; }
public string BuildDelta(IDbConnection currentDb, IDbConnection newDb, bool removeUnusedTables = false, bool removeUnusedColumns = false, bool removeUnusedTriggers = true, bool removeUnusedIndexes = true) { public string BuildDelta(IDbConnection currentDb, IDbConnection newDb, bool removeUnusedTables = false, bool removeUnusedColumns = false, bool removeUnusedTriggers = true, bool removeUnusedIndexes = true) {
Database db1 = new Database(currentDb, true); Database db1 = new Database(currentDb, true);
@@ -44,9 +46,20 @@ namespace DbTools {
public bool ApplyDelta(IDbConnection cn, string sql) { public bool ApplyDelta(IDbConnection cn, string sql) {
bool success = false; bool success = false;
using (var transaction = cn.BeginTransaction()) {
try {
using (var cmd = cn.CreateCommand()) { using (var cmd = cn.CreateCommand()) {
cmd.Transaction = transaction;
cmd.CommandText = sql; cmd.CommandText = sql;
success = cmd.ExecuteNonQuery() > 0; cmd.ExecuteNonQuery();
}
transaction.Commit();
success = true;
} catch (Exception ex) {
transaction.Rollback();
success = false;
LastError = ex;
}
} }
return success; return success;
} }
@@ -70,6 +83,8 @@ namespace DbTools {
var table1 = db1.Tables[table2.TableName]; var table1 = db1.Tables[table2.TableName];
if (table1 == null) { if (table1 == null) {
sb.AppendLine(table2.FullSql()); sb.AppendLine(table2.FullSql());
sb.AppendLine("-- TODO : Insert records from existing database");
sb.AppendLine("");
} else { } else {
// Remove unused triggers if requested // Remove unused triggers if requested
if (removeUnusedTriggers) { if (removeUnusedTriggers) {
@@ -118,6 +133,10 @@ namespace DbTools {
} }
} }
} }
if (string.IsNullOrWhiteSpace(sb.ToString().Trim())) {
sb.AppendLine("-- BOTH DATABASES ARE EQUAL - NO CHANGES ARE REQUIRED --");
}
return sb.ToString(); return sb.ToString();
} }

View File

@@ -80,10 +80,21 @@ namespace DbTools {
// Do the work // Do the work
Exception error = null; Exception error = null;
bool wasSuccessful = false; bool wasSuccessful = false;
try {
using (var transaction = dbConnection.BeginTransaction()) {
try { try {
using (var cmd = dbConnection.CreateCommand()) { using (var cmd = dbConnection.CreateCommand()) {
cmd.CommandText = File.ReadAllText(migration); cmd.CommandText = File.ReadAllText(migration);
wasSuccessful = cmd.ExecuteNonQuery() > 0; cmd.Transaction = transaction;
cmd.ExecuteNonQuery();
}
transaction.Commit();
wasSuccessful = true;
} catch (Exception ex) {
transaction.Rollback();
error = ex;
wasSuccessful = false;
}
} }
} catch (Exception ex) { } catch (Exception ex) {
error = ex; error = ex;