diff options
| author | Roy Ben-Shabat <Roy@Twine-s.com> | 2017-11-27 21:51:38 +0200 |
|---|---|---|
| committer | Roy Ben-Shabat <Roy@Twine-s.com> | 2017-11-27 21:51:38 +0200 |
| commit | df2f9b27b12356d6e92c64a72049f0fc4e6b86c0 (patch) | |
| tree | 049ced63087ef30986cc998f8546071e5894e37e /Software/Visual_Studio/Tango.Synchronization/Local | |
| parent | 7060dc80c707fc0441ff69fe4f899107cb3f6fc1 (diff) | |
| download | Tango-df2f9b27b12356d6e92c64a72049f0fc4e6b86c0.tar.gz Tango-df2f9b27b12356d6e92c64a72049f0fc4e6b86c0.zip | |
Started Remote <=> Local Synchronization... /;
Diffstat (limited to 'Software/Visual_Studio/Tango.Synchronization/Local')
5 files changed, 850 insertions, 0 deletions
diff --git a/Software/Visual_Studio/Tango.Synchronization/Local/Constants.cs b/Software/Visual_Studio/Tango.Synchronization/Local/Constants.cs new file mode 100644 index 000000000..ed8084301 --- /dev/null +++ b/Software/Visual_Studio/Tango.Synchronization/Local/Constants.cs @@ -0,0 +1,35 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tango.Synchronization.Local +{ + internal static class Constants + { + //SQLite Internal Constants + public const String SEQUENCE_TABLE_NAME = "sqlite_sequence"; + public const String TABLE_INFO = "table_info"; + public const String COLUMN_TYPE = "type"; + public const String IS_NOT_NULL = "notnull"; + public const String DEFAULT_VALUE = "dflt_value"; + + //Must Column Names. + + /// <summary> + /// The table auto incremented id column name. + /// </summary> + public const String ID = "ID"; + + /// <summary> + /// The table unique identifier column name used for synchronization. + /// </summary> + public const String GUID = "GUID"; + + /// <summary> + /// The table last updated column name used for synchronization. + /// </summary> + public const String LAST_UPDATED = "LAST_UPDATED"; + } +} diff --git a/Software/Visual_Studio/Tango.Synchronization/Local/ExtensionMethods.cs b/Software/Visual_Studio/Tango.Synchronization/Local/ExtensionMethods.cs new file mode 100644 index 000000000..8746f9146 --- /dev/null +++ b/Software/Visual_Studio/Tango.Synchronization/Local/ExtensionMethods.cs @@ -0,0 +1,88 @@ +using Tango.Synchronization; +using System; +using System.Collections.Generic; +using System.Data; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tango.Synchronization.Local +{ + internal static class SQLExtensions + { + /// <summary> + /// Gets the type of the SQL column. + /// </summary> + /// <param name="column">The column.</param> + /// <returns></returns> + public static String GetSQLType(this DataColumn column) + { + return column.ExtendedProperties[Constants.COLUMN_TYPE].ToString(); + } + + /// <summary> + /// Gets the information table. + /// </summary> + /// <param name="table">The table.</param> + /// <returns></returns> + public static DataTable GetInfoTable(this DataTable table) + { + return table.ExtendedProperties[Constants.TABLE_INFO] as DataTable; + } + + /// <summary> + /// Determines whether column is marked NOT NULL. + /// </summary> + /// <param name="column">The column.</param> + public static bool IsNotNull(this DataColumn column) + { + int value = int.Parse(column.ExtendedProperties[Constants.IS_NOT_NULL].ToString()); + return value == 0 ? false : true; + } + + /// <summary> + /// Gets the column default value. + /// </summary> + /// <param name="column">The column.</param> + /// <returns></returns> + public static String GetDefaultValue(this DataColumn column) + { + String def = column.ExtendedProperties[Constants.DEFAULT_VALUE].ToString(); + + double num = -1; + + if (double.TryParse(def, out num)) + { + return num.ToString(); + } + else + { + if (def.Contains("randomblob") || def.Contains("localtime")) + { + def = def.Insert(0, "("); + def = def.Insert(def.Length - 1, ")"); + } + return def; + } + } + + /// <summary> + /// Determines whether column definition has default value. + /// </summary> + /// <param name="column">The column.</param> + public static bool HasDefaultValue(this DataColumn column) + { + return !String.IsNullOrWhiteSpace(column.ExtendedProperties[Constants.DEFAULT_VALUE].ToString()); + } + + /// <summary> + /// Converts the DateTime instance to SQLite DateTime string. + /// </summary> + /// <param name="date">The date.</param> + /// <returns></returns> + public static String ToSQLiteDateString(this DateTime date) + { + return date.ToString("yyyy-MM-dd HH:mm:ss.fff"); + } + } +}
\ No newline at end of file diff --git a/Software/Visual_Studio/Tango.Synchronization/Local/ILocalDataBase.cs b/Software/Visual_Studio/Tango.Synchronization/Local/ILocalDataBase.cs new file mode 100644 index 000000000..7e53aeb1c --- /dev/null +++ b/Software/Visual_Studio/Tango.Synchronization/Local/ILocalDataBase.cs @@ -0,0 +1,93 @@ +using System; +using System.Collections.Generic; +using System.Data; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tango.Synchronization.Local +{ + /// <summary> + /// Represents an SQL data base adapter used by <see cref="LocalDBComparer"/>. + /// </summary> + /// <seealso cref="System.IDisposable" /> + public interface ILocalDataBase : IDisposable + { + /// <summary> + /// Gets the database source URL/File. + /// </summary> + String Source { get; } + + /// <summary> + /// Gets the database tables collection. + /// </summary> + List<DataTable> Tables { get; } + + /// <summary> + /// Loads the tables (Must be done before any synchronization). + /// </summary> + void LoadTables(); + + /// <summary> + /// Clones a table from another database into this database. + /// </summary> + /// <param name="otherDB">The other database.</param> + /// <param name="otherTable">The other table.</param> + /// <returns></returns> + DataTable CloneTableFrom(ILocalDataBase otherDB, DataTable otherTable); + + /// <summary> + /// Gets the SQL command for <see cref="CloneTableFrom(ILocalDataBase, DataTable)"/>. + /// </summary> + /// <param name="otherDB">The other database.</param> + /// <param name="otherTable">The other table.</param> + /// <returns></returns> + String GetCloneTableFromCommand(ILocalDataBase otherDB, DataTable otherTable); + + /// <summary> + /// Adds the specified column to the specified table. + /// </summary> + /// <param name="table">The table.</param> + /// <param name="column">The column.</param> + /// <returns></returns> + DataColumn AddColumn(DataTable table, DataColumn column); + + /// <summary> + /// Gets the SQL command for <see cref="AddColumn(DataTable, DataColumn)"/>. + /// </summary> + /// <param name="table">The table.</param> + /// <param name="column">The column.</param> + /// <returns></returns> + String GetAddColumnCommand(DataTable table, DataColumn column); + + /// <summary> + /// Adds the specified row to the specified table. + /// </summary> + /// <param name="table">The table.</param> + /// <param name="row">The row.</param> + void AddRow(DataTable table, DataRow row); + + /// <summary> + /// Gets the SQL command for <see cref="AddRow(DataTable, DataRow)"/>. + /// </summary> + /// <param name="table">The table.</param> + /// <param name="row">The row.</param> + /// <returns></returns> + String GetAddRowCommand(DataTable table, DataRow row); + + /// <summary> + /// Updates the matching row by the row GUID. + /// </summary> + /// <param name="table">The table.</param> + /// <param name="row">The row.</param> + void UpdateRow(DataTable table, DataRow row); + + /// <summary> + /// Gets the SQL command for <see cref="UpdateRow(DataTable, DataRow)"/>. + /// </summary> + /// <param name="table">The table.</param> + /// <param name="row">The row.</param> + /// <returns></returns> + String GetUpdateRowCommand(DataTable table, DataRow row); + } +} diff --git a/Software/Visual_Studio/Tango.Synchronization/Local/LocalDBComparer.cs b/Software/Visual_Studio/Tango.Synchronization/Local/LocalDBComparer.cs new file mode 100644 index 000000000..63f2ecfaa --- /dev/null +++ b/Software/Visual_Studio/Tango.Synchronization/Local/LocalDBComparer.cs @@ -0,0 +1,200 @@ +using System; +using System.Collections.Generic; +using System.Data; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.Logging; + +namespace Tango.Synchronization.Local +{ + /// <summary> + /// Represents an <see cref="ILocalDataBase"/> synchronization engine. + /// </summary> + /// <seealso cref="System.IDisposable" /> + public class LocalDBComparer : IDisposable + { + /// <summary> + /// Gets the master SQL. + /// </summary> + public ILocalDataBase MasterSQL { get; private set; } + + /// <summary> + /// Gets the slave SQL. + /// </summary> + public ILocalDataBase SlaveSQL { get; private set; } + + /// <summary> + /// Initializes a new instance of the <see cref="LocalDBComparer"/> class. + /// </summary> + /// <param name="masterSQL">The master SQL.</param> + /// <param name="slaveSQL">The slave SQL.</param> + public LocalDBComparer(ILocalDataBase masterSQL, ILocalDataBase slaveSQL) + { + MasterSQL = masterSQL; + SlaveSQL = slaveSQL; + } + + /// <summary> + /// Compares the master and slave SQL data base and returns a collection of <see cref="Diff"/>. + /// </summary> + /// <returns></returns> + public List<Diff> Compare() + { + LogManager.Log("Comparing databases " + Path.GetFileName(MasterSQL.Source) + " <=> " + Path.GetFileName(SlaveSQL.Source)); + + LogManager.Log("Loading master tables..."); + MasterSQL.LoadTables(); + + LogManager.Log("Loading slave tables..."); + SlaveSQL.LoadTables(); + + List<Diff> diffs = new List<Diff>(); + + foreach (var masterTable in MasterSQL.Tables) + { + LogManager.Log("Comparing table " + masterTable.TableName); + LogManager.Log("Searching table " + masterTable.TableName + " on slave..."); + + var slaveTable = SlaveSQL.Tables.SingleOrDefault(x => x.TableName == masterTable.TableName); //Get matching slave table on slave db. + + if (slaveTable == null) //Table not found on slave. + { + LogManager.Log("Table not found on slave, adding difference."); + //Clone table from slave db to master db including records! + diffs.Add(new Diff(DiffAction.AddTableToSlave, String.Format("Add table {0} to slave", masterTable.TableName), () => SlaveSQL.CloneTableFrom(MasterSQL, masterTable), SlaveSQL.GetCloneTableFromCommand(MasterSQL, masterTable))); + continue; + } + + LogManager.Log("Table found, comparing columns..."); + + foreach (DataColumn masterColumn in masterTable.Columns) + { + LogManager.Log("Searching for column " + masterColumn.ColumnName + " on slave..."); + + var slaveColumn = slaveTable.Columns[masterColumn.ColumnName]; //Get matching slave column on slave table. + + if (slaveColumn == null) //Slave column not found. + { + LogManager.Log("Column not found on slave, adding difference."); + //Add column to slave table. + diffs.Add(new Diff(DiffAction.AddColumnToSlave, String.Format("Add column {0} to slave table", masterColumn.ColumnName), () => SlaveSQL.AddColumn(masterTable, masterColumn), SlaveSQL.GetAddColumnCommand(masterTable, masterColumn))); + } + + LogManager.Log("Column found."); + } + + List<DataRow> addToSlave = new List<DataRow>(); + List<DataRow> updateSlave = new List<DataRow>(); + List<DataRow> addToMaster = new List<DataRow>(); + List<DataRow> updateMaster = new List<DataRow>(); + + LogManager.Log("Comparing rows..."); + + int count = 0; + + foreach (DataRow masterRow in masterTable.Rows) + { + LogManager.Log("Comparing row " + count++); + + String guid = masterRow.Field<String>(Constants.GUID); + + LogManager.Log("Searching for row with GUID " + guid + " on slave table..."); + + //Get Matching slave row. + DataRow slaveRow = slaveTable.AsEnumerable().SingleOrDefault(x => x.Field<String>(Constants.GUID) == guid); + + if (slaveRow != null) + { + LogManager.Log("Slave row found, comparing dates..."); + + DateTime masterDate = masterRow.Field<DateTime>(Constants.LAST_UPDATED); + DateTime slaveDate = slaveRow.Field<DateTime>(Constants.LAST_UPDATED); + + if (masterDate > slaveDate) + { + LogManager.Log("Master => Slave Update " + masterDate.ToSQLiteDateString() + ", adding difference."); + updateSlave.Add(masterRow); + } + else if (slaveDate > masterDate) + { + LogManager.Log("Master <= Slave Update " + masterDate.ToSQLiteDateString() + ", adding difference."); + updateMaster.Add(slaveRow); + } + else + { + LogManager.Log("Master <=> Slave No Update."); + } + } + else + { + LogManager.Log("Slave row not found, adding difference."); + addToSlave.Add(masterRow); + } + } + + LogManager.Log("Done comparing rows..."); + + LogManager.Log("Searching for missing rows on master..."); + + foreach (DataRow slaveRow in slaveTable.Rows) + { + String guid = slaveRow.Field<String>(Constants.GUID); + + LogManager.Log("Searching for row with GUID " + guid + " on master table..."); + + //Get Matching slave row. + DataRow masterRow = masterTable.AsEnumerable().SingleOrDefault(x => x.Field<String>(Constants.GUID) == guid); + + if (masterRow == null) + { + LogManager.Log("Master row not found, adding difference."); + addToMaster.Add(slaveRow); + } + else + { + LogManager.Log("Master row found."); + } + } + + LogManager.Log("Done searching for missing rows on master..."); + + foreach (var row in addToSlave) + { + diffs.Add(new Diff(DiffAction.AddRowToSlave, String.Format("Add row to slave table {0}", slaveTable.TableName), () => SlaveSQL.AddRow(slaveTable, row), SlaveSQL.GetAddRowCommand(slaveTable, row))); + } + + foreach (var row in addToMaster) + { + diffs.Add(new Diff(DiffAction.AddRowToMaster, String.Format("Add row to master table {0}", masterTable.TableName), () => MasterSQL.AddRow(masterTable, row), MasterSQL.GetAddRowCommand(masterTable, row))); + } + + foreach (var row in updateSlave) + { + diffs.Add(new Diff(DiffAction.UpdateRowInSlave, String.Format("Update row in slave table {0}", slaveTable.TableName), () => SlaveSQL.UpdateRow(slaveTable, row), SlaveSQL.GetUpdateRowCommand(slaveTable, row))); + } + + foreach (var row in updateMaster) + { + diffs.Add(new Diff(DiffAction.UpdateRowInMaster, String.Format("Update row in master table {0}", masterTable.TableName), () => MasterSQL.UpdateRow(masterTable, row), MasterSQL.GetUpdateRowCommand(masterTable, row))); + } + + LogManager.Log("Done comparing table " + masterTable.TableName); + } + + LogManager.Log("Databases comparison completed."); + + return diffs; + } + + /// <summary> + /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. + /// </summary> + public void Dispose() + { + MasterSQL.Dispose(); + SlaveSQL.Dispose(); + } + } +} diff --git a/Software/Visual_Studio/Tango.Synchronization/Local/SqliteDataBase.cs b/Software/Visual_Studio/Tango.Synchronization/Local/SqliteDataBase.cs new file mode 100644 index 000000000..35e54c66a --- /dev/null +++ b/Software/Visual_Studio/Tango.Synchronization/Local/SqliteDataBase.cs @@ -0,0 +1,434 @@ +using Tango.Synchronization; +using System; +using System.Collections.Generic; +using System.Data; +using System.Data.SQLite; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tango.Synchronization.Local +{ + /// <summary> + /// Represents an SQLite database adapter used for synchronization by <see cref="LocalDBComparer"/>. + /// </summary> + /// <seealso cref="Tango.Synchronization.ISqlDataBase" /> + public class SQLiteDataBase : ILocalDataBase + { + private SQLiteConnection _connection; + + /// <summary> + /// Gets the database source URL/File. + /// </summary> + public String Source { get; private set; } + + /// <summary> + /// Gets the database tables collection. + /// </summary> + public List<DataTable> Tables { get; private set; } + + /// <summary> + /// Initializes a new instance of the <see cref="SQLiteDataBase"/> class. + /// </summary> + /// <param name="filePath">The file path.</param> + public SQLiteDataBase(String filePath) + { + Source = filePath; + + _connection = new SQLiteConnection(String.Format("Data Source={0};Version=3;New={1};Compress=FALSE;", + filePath, + (File.Exists(filePath) ? "False" : "True") + )); + + _connection.Open(); + } + + /// <summary> + /// Loads the tables (Must be done before any synchronization). + /// </summary> + public void LoadTables() + { + Tables = new List<DataTable>(); + + var command = _connection.CreateCommand(); + command.CommandText = "SELECT name FROM sqlite_master WHERE type = 'table'"; + var reader = command.ExecuteReader(); + + while (reader.Read()) + { + String name = reader.GetString(0); + + if (name != Constants.SEQUENCE_TABLE_NAME) + { + Debug.WriteLine(name); + Tables.Add(LoadTable(name)); + } + } + } + + /// <summary> + /// Loads the table. + /// </summary> + /// <param name="name">The name.</param> + /// <returns></returns> + private DataTable LoadTable(String name) + { + var tableCommand = _connection.CreateCommand(); + tableCommand.CommandText = "SELECT * FROM " + name; + + DataTable table = new DataTable(name); + table.Load(tableCommand.ExecuteReader()); + + var infoCommand = _connection.CreateCommand(); + infoCommand.CommandText = String.Format("PRAGMA table_info({0});", name); + DataTable infoTable = new DataTable(name); + infoTable.Load(infoCommand.ExecuteReader()); + + table.ExtendedProperties.Add(Constants.TABLE_INFO, infoTable); + + for (int i = 0; i < table.Columns.Count; i++) + { + DataColumn column = table.Columns[i]; + column.ExtendedProperties.Add(Constants.COLUMN_TYPE, infoTable.Rows[i][Constants.COLUMN_TYPE]); + column.ExtendedProperties.Add(Constants.IS_NOT_NULL, infoTable.Rows[i][Constants.IS_NOT_NULL]); + column.ExtendedProperties.Add(Constants.DEFAULT_VALUE, infoTable.Rows[i][Constants.DEFAULT_VALUE]); + } + + return table; + } + + /// <summary> + /// Clones a table from another database into this database. + /// </summary> + /// <param name="otherDB">The other database.</param> + /// <param name="otherTable">The other table.</param> + /// <returns></returns> + public DataTable CloneTableFrom(ILocalDataBase otherDB, DataTable otherTable) + { + String cmd = String.Format("CREATE TABLE {0} (", otherTable.TableName); + + foreach (DataColumn column in otherTable.Columns) + { + cmd += String.Format("{0} {1} {2} {3} {4} {5}", + column.ColumnName, + column.GetSQLType(), + otherTable.PrimaryKey.Contains(column) ? "PRIMARY KEY" : null, + column.Unique ? "UNIQUE" : null, + column.IsNotNull() ? "NOT NULL" : null, + column.HasDefaultValue() ? ("DEFAULT " + column.GetDefaultValue()) : null) + + + ", " + Environment.NewLine; + } + + cmd += ");"; + + cmd = cmd.Remove(cmd.LastIndexOf(","), 1); + + var createCommand = _connection.CreateCommand(); + createCommand.CommandText = cmd; + createCommand.ExecuteNonQuery(); + + var attacheCommand = _connection.CreateCommand(); + attacheCommand.CommandText = String.Format("ATTACH DATABASE '{0}' AS other;", otherDB.Source); + attacheCommand.ExecuteNonQuery(); + + var copyCommand = _connection.CreateCommand(); + copyCommand.CommandText = String.Format("INSERT INTO main.{0} SELECT * FROM {1}.{0};", otherTable.TableName, "other"); + copyCommand.ExecuteNonQuery(); + + var detacheCommand = _connection.CreateCommand(); + detacheCommand.CommandText = "DETACH other;"; + detacheCommand.ExecuteNonQuery(); + + var table = LoadTable(otherTable.TableName); + Tables.Add(table); + return table; + } + + /// <summary> + /// Gets the SQL command for <see cref="CloneTableFrom(ILocalDataBase, DataTable)" />. + /// </summary> + /// <param name="otherDB">The other database.</param> + /// <param name="otherTable">The other table.</param> + /// <returns></returns> + public String GetCloneTableFromCommand(ILocalDataBase otherDB, DataTable otherTable) + { + String cmd = String.Format("CREATE TABLE {0} (", otherTable.TableName); + + foreach (DataColumn column in otherTable.Columns) + { + cmd += String.Format("{0} {1} {2} {3} {4} {5}", + column.ColumnName, + column.GetSQLType(), + otherTable.PrimaryKey.Contains(column) ? "PRIMARY KEY" : null, + column.Unique ? "UNIQUE" : null, + column.IsNotNull() ? "NOT NULL" : null, + column.HasDefaultValue() ? ("DEFAULT " + column.GetDefaultValue()) : null) + + + ", " + Environment.NewLine; + } + + cmd += ");"; + + cmd = cmd.Remove(cmd.LastIndexOf(","), 1); + + cmd += Environment.NewLine; + + cmd += String.Format("ATTACH DATABASE '{0}' AS other;", otherDB.Source); + + cmd += Environment.NewLine; + + cmd += String.Format("INSERT INTO main.{0} SELECT * FROM {1}.{0};", otherTable.TableName, "other"); + + cmd += Environment.NewLine; + + cmd += "DETACH other;"; + + return cmd; + } + + /// <summary> + /// Adds the specified column to the specified table. + /// </summary> + /// <param name="table">The table.</param> + /// <param name="column">The column.</param> + /// <returns></returns> + public DataColumn AddColumn(DataTable table, DataColumn column) + { + var insertCommand = _connection.CreateCommand(); + insertCommand.CommandText = String.Format("ALTER TABLE {0} ADD COLUMN {1} {2} {3} {4} {5} {6}", + table.TableName, + column.ColumnName, + column.GetSQLType(), + table.PrimaryKey.Contains(column) ? "PRIMARY KEY" : null, + column.Unique ? "UNIQUE" : null, + column.IsNotNull() ? "NOT NULL" : null, + column.HasDefaultValue() ? ("DEFAULT " + column.GetDefaultValue()) : null); + + + insertCommand.ExecuteNonQuery(); + var t = LoadTable(table.TableName); + var index = Tables.IndexOf(Tables.Single(x => x.TableName == table.TableName)); + Tables[index] = t; + return t.Columns[column.ColumnName]; + } + + /// <summary> + /// Gets the SQL command for <see cref="AddColumn(DataTable, DataColumn)" />. + /// </summary> + /// <param name="table">The table.</param> + /// <param name="column">The column.</param> + /// <returns></returns> + public String GetAddColumnCommand(DataTable table, DataColumn column) + { + String cmd = String.Format("ALTER TABLE {0} ADD COLUMN {1} {2} {3} {4} {5} {6}", + table.TableName, + column.ColumnName, + column.GetSQLType(), + table.PrimaryKey.Contains(column) ? "PRIMARY KEY" : null, + column.Unique ? "UNIQUE" : null, + column.IsNotNull() ? "NOT NULL" : null, + column.HasDefaultValue() ? ("DEFAULT " + column.GetDefaultValue()) : null); + + return cmd; + } + + /// <summary> + /// Adds the specified row to the specified table. + /// </summary> + /// <param name="table">The table.</param> + /// <param name="row">The row.</param> + public void AddRow(DataTable table, DataRow row) + { + var insertCommand = _connection.CreateCommand(); + + List<String> values = new List<string>(); + + for (int i = 0; i < row.ItemArray.Length; i++) + { + String value = row.ItemArray[i].ToString(); + + double num = 0; + + if (row.ItemArray[i].GetType() == typeof(DateTime)) + { + value = ((DateTime)row.ItemArray[i]).ToSQLiteDateString(); + } + + if (!double.TryParse(value, out num)) + { + value = "'" + value + "'"; + } + + values.Add(value); + } + + insertCommand.CommandText = String.Format("INSERT INTO {0} VALUES({1});", table.TableName, String.Join(",", values)); + insertCommand.ExecuteNonQuery(); + + var desRow = table.NewRow(); + desRow.ItemArray = row.ItemArray.Clone() as object[]; + } + + /// <summary> + /// Gets the SQL command for <see cref="AddRow(DataTable, DataRow)" />. + /// </summary> + /// <param name="table">The table.</param> + /// <param name="row">The row.</param> + /// <returns></returns> + public String GetAddRowCommand(DataTable table, DataRow row) + { + List<String> values = new List<string>(); + + for (int i = 0; i < row.ItemArray.Length; i++) + { + String value = row.ItemArray[i].ToString(); + + double num = 0; + + if (row.ItemArray[i].GetType() == typeof(DateTime)) + { + value = ((DateTime)row.ItemArray[i]).ToSQLiteDateString(); + } + + if (!double.TryParse(value, out num)) + { + value = "'" + value + "'"; + } + + values.Add(value); + } + + String cmd = String.Format("INSERT INTO {0} VALUES({1});", table.TableName, String.Join("," + Environment.NewLine, values)); + return cmd; + } + + /// <summary> + /// Updates the matching row by the row GUID. + /// </summary> + /// <param name="table">The table.</param> + /// <param name="row">The row.</param> + public void UpdateRow(DataTable table, DataRow row) + { + var updateCommand = _connection.CreateCommand(); + + List<String> values = new List<string>(); + + for (int i = 0; i < row.ItemArray.Length; i++) + { + String value = row.ItemArray[i].ToString(); + + double num = 0; + + if (row.ItemArray[i].GetType() == typeof(DateTime)) + { + value = ((DateTime)row.ItemArray[i]).ToSQLiteDateString(); + } + + if (!double.TryParse(value, out num)) + { + value = "'" + value + "'"; + } + + values.Add(value); + } + + String cmd = String.Format("UPDATE {0} SET ", table.TableName); + + String guid = String.Empty; + + for (int columnIndex = 0; columnIndex < table.Columns.Count; columnIndex++) + { + DataColumn column = table.Columns[columnIndex]; + if (column.ColumnName == Constants.ID) + { + continue; + } + else if (column.ColumnName == Constants.GUID) + { + guid = values[columnIndex]; + continue; + } + + cmd += String.Format("{0} = {1},{2}", column.ColumnName, values[columnIndex], Environment.NewLine); + } + + cmd = cmd.Remove(cmd.LastIndexOf(","), 1); + + cmd += "WHERE" + Environment.NewLine; + cmd += String.Format("{0} = {1};", Constants.GUID, guid); + + updateCommand.CommandText = cmd; + updateCommand.ExecuteNonQuery(); + var desRow = table.NewRow(); + desRow.ItemArray = row.ItemArray.Clone() as object[]; + } + + /// <summary> + /// Gets the SQL command for <see cref="UpdateRow(DataTable, DataRow)" />. + /// </summary> + /// <param name="table">The table.</param> + /// <param name="row">The row.</param> + /// <returns></returns> + public String GetUpdateRowCommand(DataTable table, DataRow row) + { + List<String> values = new List<string>(); + + for (int i = 0; i < row.ItemArray.Length; i++) + { + String value = row.ItemArray[i].ToString(); + + double num = 0; + + if (row.ItemArray[i].GetType() == typeof(DateTime)) + { + value = ((DateTime)row.ItemArray[i]).ToSQLiteDateString(); + } + + if (!double.TryParse(value, out num)) + { + value = "'" + value + "'"; + } + + values.Add(value); + } + + String cmd = String.Format("UPDATE {0} SET ", table.TableName); + + String guid = String.Empty; + + for (int columnIndex = 0; columnIndex < table.Columns.Count; columnIndex++) + { + DataColumn column = table.Columns[columnIndex]; + if (column.ColumnName == Constants.ID) + { + continue; + } + else if (column.ColumnName == Constants.GUID) + { + guid = values[columnIndex]; + continue; + } + + cmd += String.Format("{0} = {1},{2}", column.ColumnName, values[columnIndex], Environment.NewLine); + } + + cmd = cmd.Remove(cmd.LastIndexOf(","), 1); + + cmd += "WHERE" + Environment.NewLine; + cmd += String.Format("{0} = {1};", Constants.GUID, guid); + + return cmd; + } + + /// <summary> + /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. + /// </summary> + public void Dispose() + { + _connection.Close(); + } + } +} |
