From c38add376a2ba4bb7312d418e30b2fd779d3ffda Mon Sep 17 00:00:00 2001 From: inga-lovinde <52715130+inga-lovinde@users.noreply.github.com> Date: Mon, 14 Jun 2010 16:09:35 +0000 Subject: [PATCH] High-level DB modify methods implemented (actions, changes, changesets); Thread.incrementViewsCounter() implemented --- Builder/IISMainHandler/build.txt | 2 +- Common/Common.csproj | 10 +++ Common/ISqlObjectTableSpec.cs | 11 +++ Common/SqlObject.cs | 7 +- Common/actions/AbstractChange.cs | 39 +++++++++ Common/actions/AbstractFieldValue.cs | 13 +++ Common/actions/ChangeSet.cs | 100 +++++++++++++++++++++++ Common/actions/IncrementFieldValue.cs | 27 ++++++ Common/actions/InsertChange.cs | 38 +++++++++ Common/actions/InsertOrUpdateChange.cs | 68 +++++++++++++++ Common/actions/ReferenceFieldValue.cs | 23 ++++++ Common/actions/ScalarFieldValue.cs | 23 ++++++ Common/actions/UpdateChange.cs | 40 +++++++++ Common/dataobjects/Board.cs | 5 +- Common/dataobjects/Category.cs | 5 +- Common/dataobjects/Post.cs | 5 +- Common/dataobjects/Thread.cs | 26 +++++- Common/dataobjects/User.cs | 5 +- IISMainHandler/handlers/PostHandler.cs | 1 + IISMainHandler/handlers/ThreadHandler.cs | 1 + MySQLConnector/ConditionCompiler.cs | 10 +-- MySQLConnector/Connection.cs | 3 +- 22 files changed, 444 insertions(+), 18 deletions(-) create mode 100644 Common/ISqlObjectTableSpec.cs create mode 100644 Common/actions/AbstractChange.cs create mode 100644 Common/actions/AbstractFieldValue.cs create mode 100644 Common/actions/ChangeSet.cs create mode 100644 Common/actions/IncrementFieldValue.cs create mode 100644 Common/actions/InsertChange.cs create mode 100644 Common/actions/InsertOrUpdateChange.cs create mode 100644 Common/actions/ReferenceFieldValue.cs create mode 100644 Common/actions/ScalarFieldValue.cs create mode 100644 Common/actions/UpdateChange.cs diff --git a/Builder/IISMainHandler/build.txt b/Builder/IISMainHandler/build.txt index a14c1ee..946b551 100644 --- a/Builder/IISMainHandler/build.txt +++ b/Builder/IISMainHandler/build.txt @@ -1 +1 @@ -180 \ No newline at end of file +191 \ No newline at end of file diff --git a/Common/Common.csproj b/Common/Common.csproj index 921c810..a4a1fa3 100644 --- a/Common/Common.csproj +++ b/Common/Common.csproj @@ -45,6 +45,15 @@ + + + + + + + + + @@ -54,6 +63,7 @@ + diff --git a/Common/ISqlObjectTableSpec.cs b/Common/ISqlObjectTableSpec.cs new file mode 100644 index 0000000..fff6dcc --- /dev/null +++ b/Common/ISqlObjectTableSpec.cs @@ -0,0 +1,11 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using FLocal.Core.DB; + +namespace FLocal.Common { + public interface ISqlObjectTableSpec : ITableSpec { + void refreshSqlObject(int id); + } +} diff --git a/Common/SqlObject.cs b/Common/SqlObject.cs index 93ff805..67c3823 100644 --- a/Common/SqlObject.cs +++ b/Common/SqlObject.cs @@ -11,7 +11,7 @@ namespace FLocal.Common { protected SqlObject() : base() { } - abstract protected ITableSpec table { + abstract protected ISqlObjectTableSpec table { get; } @@ -116,5 +116,10 @@ namespace FLocal.Common { return res; } + protected static void Refresh(int id) { + Dictionary objects = LoadByIdsForLoadingFromHash(new List() { id }); + objects[id].ReLoad(); + } + } } diff --git a/Common/actions/AbstractChange.cs b/Common/actions/AbstractChange.cs new file mode 100644 index 0000000..9c45ee2 --- /dev/null +++ b/Common/actions/AbstractChange.cs @@ -0,0 +1,39 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using FLocal.Core.DB; + +namespace FLocal.Common.actions { + abstract class AbstractChange { + + private bool isApplied; + + abstract public int? getId(); + + abstract public void Lock(Transaction transaction); + + abstract protected void doApply(Transaction transaction); + + public void Apply(Transaction transaction) { + if(!this.isApplied) { + this.doApply(transaction); + this.isApplied = true; + } + } + + public readonly IEnumerable references; + + public readonly ISqlObjectTableSpec tableSpec; + + protected readonly Dictionary data; + + protected AbstractChange(ISqlObjectTableSpec tableSpec, Dictionary data) { + this.tableSpec = tableSpec; + this.data = data; + this.references = from kvp in data where kvp.Value is ReferenceFieldValue select ((ReferenceFieldValue)kvp.Value).referenced; + this.isApplied = false; + } + + } +} diff --git a/Common/actions/AbstractFieldValue.cs b/Common/actions/AbstractFieldValue.cs new file mode 100644 index 0000000..d2dc111 --- /dev/null +++ b/Common/actions/AbstractFieldValue.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace FLocal.Common.actions { + abstract class AbstractFieldValue { + + abstract public string getStringRepresentation(); + abstract public string getStringRepresentation(string oldInfo); + + } +} diff --git a/Common/actions/ChangeSet.cs b/Common/actions/ChangeSet.cs new file mode 100644 index 0000000..7474954 --- /dev/null +++ b/Common/actions/ChangeSet.cs @@ -0,0 +1,100 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using FLocal.Core; +using FLocal.Core.DB; + +namespace FLocal.Common.actions { + + /// + /// Note that you should create ChangeSet instances outside of transactions they're using! + /// Otherwise, there will be a 100% DB deadlock in Dispose (or data in registry won't update) + /// + class ChangeSet : IDisposable { + + private static readonly object tablesLockOrder_locker = new object(); + private static IEnumerable tablesLockOrder { + get { + return Cache>.instance.get( + tablesLockOrder_locker, + () => new List() { + "Boards", + "Threads", + "Posts", + } + ); + } + } + + private object locker = new object(); + + private bool isAdding; + private bool isProcessing; + private bool isProcessed; + + private Dictionary> changesByTable; + + public ChangeSet() { + this.isAdding = false; + this.isProcessing = false; + this.isProcessed = false; + this.changesByTable = new Dictionary>(); + foreach(string table in tablesLockOrder) { + this.changesByTable[table] = new HashSet(); + } + } + + public void Add(AbstractChange change) { + lock(locker) { + if(this.isAdding) throw new CriticalException("Cannot add inside add"); + if(this.isProcessing || this.isProcessed) throw new CriticalException("ChangeSet is readonly"); + this.isAdding = true; + } + if(!this.changesByTable.ContainsKey(change.tableSpec.name)) throw new CriticalException("Table not supported"); + this.changesByTable[change.tableSpec.name].Add(change); + this.isAdding = false; + foreach(AbstractChange referencedChange in change.references) { + this.Add(referencedChange); + } + } + + private void ApplyToChange(Transaction transaction, AbstractChange change) { + foreach(AbstractChange referenced in change.references) { + if(!referenced.getId().HasValue) { + this.ApplyToChange(transaction, referenced); + } + } + change.Apply(transaction); + } + + public void Apply(Transaction transaction) { + lock(this.locker) { + if(this.isAdding) throw new CriticalException("Cannot process while adding"); + if(this.isProcessing || this.isProcessed) throw new CriticalException("ChangeSet is already processed"); + this.isProcessing = true; + } + foreach(string table in tablesLockOrder) { + foreach(AbstractChange change in (from AbstractChange _change in this.changesByTable[table] orderby _change.getId() select _change)) { + change.Lock(transaction); + } + } + foreach(KeyValuePair> kvp in this.changesByTable) { + foreach(AbstractChange change in kvp.Value) { + this.ApplyToChange(transaction, change); + } + } + this.isProcessed = true; + } + + public void Dispose() { + //if(!this.isProcessed) throw new CriticalException("ChangeSet is not processed yet"); + foreach(KeyValuePair> kvp in this.changesByTable) { + foreach(AbstractChange change in kvp.Value) { + change.tableSpec.refreshSqlObject(change.getId().Value); + } + } + } + + } +} diff --git a/Common/actions/IncrementFieldValue.cs b/Common/actions/IncrementFieldValue.cs new file mode 100644 index 0000000..cf739e1 --- /dev/null +++ b/Common/actions/IncrementFieldValue.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace FLocal.Common.actions { + class IncrementFieldValue : AbstractFieldValue { + + private readonly Func incrementor; + + public IncrementFieldValue(Func incrementor) { + this.incrementor = incrementor; + } + + public IncrementFieldValue() + : this(str => (int.Parse(str)+1).ToString()) { + } + + public override string getStringRepresentation() { + throw new NotSupportedException(); + } + public override string getStringRepresentation(string oldInfo) { + return this.incrementor(oldInfo); + } + + } +} diff --git a/Common/actions/InsertChange.cs b/Common/actions/InsertChange.cs new file mode 100644 index 0000000..c8bf5fb --- /dev/null +++ b/Common/actions/InsertChange.cs @@ -0,0 +1,38 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using FLocal.Core.DB; + +namespace FLocal.Common.actions { + class InsertChange : AbstractChange { + + private int? id; + + public InsertChange(ISqlObjectTableSpec tableSpec, Dictionary data, int id) + : base(tableSpec, data) { + this.id = null; + } + + public override int? getId() { + return this.id; + } + + public override void Lock(Transaction transaction) { + Config.instance.mainConnection.lockTable(transaction, this.tableSpec); + } + + protected override void doApply(Transaction transaction) { + Dictionary processedData = new Dictionary(); + foreach(KeyValuePair kvp in this.data) { + processedData[kvp.Key] = kvp.Value.getStringRepresentation(); + } + this.id = int.Parse(Config.instance.mainConnection.insert( + transaction, + this.tableSpec, + processedData + )); + } + + } +} diff --git a/Common/actions/InsertOrUpdateChange.cs b/Common/actions/InsertOrUpdateChange.cs new file mode 100644 index 0000000..3421ca7 --- /dev/null +++ b/Common/actions/InsertOrUpdateChange.cs @@ -0,0 +1,68 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using FLocal.Core; +using FLocal.Core.DB; +using FLocal.Core.DB.conditions; + +namespace FLocal.Common.actions { + class InsertOrUpdateChange : AbstractChange { + + private int? id; + + private AbstractCondition condition; + + public InsertOrUpdateChange(ISqlObjectTableSpec tableSpec, Dictionary data, AbstractCondition condition) + : base(tableSpec, data) { + this.id = null; + this.condition = condition; + } + + public override int? getId() { + return this.id; + } + + public override void Lock(Transaction transaction) { + List ids = Config.instance.mainConnection.LoadIdsByConditions(this.tableSpec, this.condition, Diapasone.unlimited, new JoinSpec[0]); + if(ids.Count > 1) { + throw new CriticalException("Not unique"); + } else if(ids.Count == 1) { + this.id = int.Parse(ids[0]); + Config.instance.mainConnection.lockRow(transaction, this.tableSpec, this.id.ToString()); + } else { + Config.instance.mainConnection.lockTable(transaction, this.tableSpec); + ids = Config.instance.mainConnection.LoadIdsByConditions(this.tableSpec, this.condition, Diapasone.unlimited, new JoinSpec[0]); + if(ids.Count > 1) { + throw new CriticalException("Not unique"); + } else if(ids.Count == 1) { + this.id = int.Parse(ids[0]); + } else { + this.id = null; + } + } + } + + protected override void doApply(Transaction transaction) { + Dictionary processedData = new Dictionary(); + foreach(KeyValuePair kvp in this.data) { + processedData[kvp.Key] = kvp.Value.getStringRepresentation(); + } + if(this.id.HasValue) { + Config.instance.mainConnection.update( + transaction, + this.tableSpec, + this.id.ToString(), + processedData + ); + } else { + Config.instance.mainConnection.insert( + transaction, + this.tableSpec, + processedData + ); + } + } + + } +} diff --git a/Common/actions/ReferenceFieldValue.cs b/Common/actions/ReferenceFieldValue.cs new file mode 100644 index 0000000..4b392b4 --- /dev/null +++ b/Common/actions/ReferenceFieldValue.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace FLocal.Common.actions { + class ReferenceFieldValue : AbstractFieldValue { + + public readonly AbstractChange referenced; + + public ReferenceFieldValue(AbstractChange referenced) { + this.referenced = referenced; + } + + public override string getStringRepresentation() { + return this.referenced.getId().Value.ToString(); + } + public override string getStringRepresentation(string oldInfo) { + return this.referenced.getId().Value.ToString(); + } + + } +} diff --git a/Common/actions/ScalarFieldValue.cs b/Common/actions/ScalarFieldValue.cs new file mode 100644 index 0000000..a0a42af --- /dev/null +++ b/Common/actions/ScalarFieldValue.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace FLocal.Common.actions { + class ScalarFieldValue : AbstractFieldValue { + + private readonly string scalar; + + public ScalarFieldValue(string scalar) { + this.scalar = scalar; + } + + public override string getStringRepresentation() { + return this.scalar; + } + public override string getStringRepresentation(string oldInfo) { + return this.scalar; + } + + } +} diff --git a/Common/actions/UpdateChange.cs b/Common/actions/UpdateChange.cs new file mode 100644 index 0000000..83c6d29 --- /dev/null +++ b/Common/actions/UpdateChange.cs @@ -0,0 +1,40 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using FLocal.Core.DB; + +namespace FLocal.Common.actions { + class UpdateChange : AbstractChange { + + private readonly int id; + + public UpdateChange(ISqlObjectTableSpec tableSpec, Dictionary data, int id) + : base(tableSpec, data) { + this.id = id; + } + + public override int? getId() { + return this.id; + } + + public override void Lock(Transaction transaction) { + Config.instance.mainConnection.lockRow(transaction, this.tableSpec, this.id.ToString()); + } + + protected override void doApply(Transaction transaction) { + Dictionary row = Config.instance.mainConnection.LoadByIds(transaction, this.tableSpec, new List() { this.id.ToString() })[0]; + Dictionary processedData = new Dictionary(); + foreach(KeyValuePair kvp in this.data) { + processedData[kvp.Key] = kvp.Value.getStringRepresentation(row[kvp.Key]); + } + Config.instance.mainConnection.update( + transaction, + this.tableSpec, + this.id.ToString(), + processedData + ); + } + + } +} diff --git a/Common/dataobjects/Board.cs b/Common/dataobjects/Board.cs index c76955f..e26da2a 100644 --- a/Common/dataobjects/Board.cs +++ b/Common/dataobjects/Board.cs @@ -10,7 +10,7 @@ using FLocal.Core.DB.conditions; namespace FLocal.Common.dataobjects { public class Board : SqlObject { - public class TableSpec : FLocal.Core.DB.ITableSpec { + public class TableSpec : ISqlObjectTableSpec { public const string TABLE = "Boards"; public const string FIELD_ID = "Id"; public const string FIELD_SORTORDER = "SortOrder"; @@ -24,9 +24,10 @@ namespace FLocal.Common.dataobjects { public static readonly TableSpec instance = new TableSpec(); public string name { get { return TABLE; } } public string idName { get { return FIELD_ID; } } + public void refreshSqlObject(int id) { Refresh(id); } } - protected override FLocal.Core.DB.ITableSpec table { get { return TableSpec.instance; } } + protected override ISqlObjectTableSpec table { get { return TableSpec.instance; } } private int _sortOrder; public int sortOrder { diff --git a/Common/dataobjects/Category.cs b/Common/dataobjects/Category.cs index 56c4df4..a7e0368 100644 --- a/Common/dataobjects/Category.cs +++ b/Common/dataobjects/Category.cs @@ -9,7 +9,7 @@ using System.Xml.Linq; namespace FLocal.Common.dataobjects { public class Category : SqlObject { - public class TableSpec : ITableSpec { + public class TableSpec : ISqlObjectTableSpec { public const string TABLE = "Categories"; public const string FIELD_ID = "Id"; public const string FIELD_SORTORDER = "SortOrder"; @@ -18,9 +18,10 @@ namespace FLocal.Common.dataobjects { public static readonly TableSpec instance = new TableSpec(); public string name { get { return TABLE; } } public string idName { get { return FIELD_ID; } } + public void refreshSqlObject(int id) { Refresh(id); } } - protected override ITableSpec table { get { return TableSpec.instance; } } + protected override ISqlObjectTableSpec table { get { return TableSpec.instance; } } private string _name; public string name { diff --git a/Common/dataobjects/Post.cs b/Common/dataobjects/Post.cs index d2dcc33..bd95ec1 100644 --- a/Common/dataobjects/Post.cs +++ b/Common/dataobjects/Post.cs @@ -9,7 +9,7 @@ using FLocal.Core.DB; namespace FLocal.Common.dataobjects { public class Post : SqlObject { - public class TableSpec : FLocal.Core.DB.ITableSpec { + public class TableSpec : ISqlObjectTableSpec { public const string TABLE = "Posts"; public const string FIELD_ID = "Id"; public const string FIELD_POSTERID = "PosterId"; @@ -24,9 +24,10 @@ namespace FLocal.Common.dataobjects { public static readonly TableSpec instance = new TableSpec(); public string name { get { return TABLE; } } public string idName { get { return FIELD_ID; } } + public void refreshSqlObject(int id) { Refresh(id); } } - protected override FLocal.Core.DB.ITableSpec table { get { return TableSpec.instance; } } + protected override ISqlObjectTableSpec table { get { return TableSpec.instance; } } private int _posterId; public int posterId { diff --git a/Common/dataobjects/Thread.cs b/Common/dataobjects/Thread.cs index 10c281f..873c1b2 100644 --- a/Common/dataobjects/Thread.cs +++ b/Common/dataobjects/Thread.cs @@ -6,11 +6,12 @@ using System.Xml.Linq; using FLocal.Core; using FLocal.Core.DB; using FLocal.Core.DB.conditions; +using FLocal.Common.actions; namespace FLocal.Common.dataobjects { public class Thread : SqlObject { - public class TableSpec : FLocal.Core.DB.ITableSpec { + public class TableSpec : ISqlObjectTableSpec { public const string TABLE = "Threads"; public const string FIELD_ID = "Id"; public const string FIELD_BOARDID = "BoardId"; @@ -26,9 +27,10 @@ namespace FLocal.Common.dataobjects { public static readonly TableSpec instance = new TableSpec(); public string name { get { return TABLE; } } public string idName { get { return FIELD_ID; } } + public void refreshSqlObject(int id) { Refresh(id); } } - protected override FLocal.Core.DB.ITableSpec table { get { return TableSpec.instance; } } + protected override ISqlObjectTableSpec table { get { return TableSpec.instance; } } private int _boardId; public int boardId { @@ -193,5 +195,25 @@ namespace FLocal.Common.dataobjects { ); } + public void incrementViewsCounter() { + using(ChangeSet changeSet = new ChangeSet()) { + changeSet.Add(new UpdateChange( + TableSpec.instance, + new Dictionary() { + { + TableSpec.FIELD_TOTALVIEWS, + new IncrementFieldValue() + } + }, + this.id + )); + using(Transaction transaction = Config.instance.mainConnection.beginTransaction()) { + changeSet.Apply(transaction); + transaction.Commit(); + } + } + } + } + } diff --git a/Common/dataobjects/User.cs b/Common/dataobjects/User.cs index 81349ac..5493d14 100644 --- a/Common/dataobjects/User.cs +++ b/Common/dataobjects/User.cs @@ -9,7 +9,7 @@ using FLocal.Core.DB; namespace FLocal.Common.dataobjects { public class User : SqlObject { - public class TableSpec : FLocal.Core.DB.ITableSpec { + public class TableSpec : ISqlObjectTableSpec { public const string TABLE = "Users"; public const string FIELD_ID = "Id"; public const string FIELD_REGDATE = "RegDate"; @@ -23,9 +23,10 @@ namespace FLocal.Common.dataobjects { public static readonly TableSpec instance = new TableSpec(); public string name { get { return TABLE; } } public string idName { get { return FIELD_ID; } } + public void refreshSqlObject(int id) { Refresh(id); } } - protected override FLocal.Core.DB.ITableSpec table { get { return TableSpec.instance; } } + protected override ISqlObjectTableSpec table { get { return TableSpec.instance; } } private DateTime _regDate; public DateTime regDate { diff --git a/IISMainHandler/handlers/PostHandler.cs b/IISMainHandler/handlers/PostHandler.cs index 36fb2ec..2bbc9dc 100644 --- a/IISMainHandler/handlers/PostHandler.cs +++ b/IISMainHandler/handlers/PostHandler.cs @@ -19,6 +19,7 @@ namespace FLocal.IISHandler.handlers { override protected XElement[] getSpecificData(WebContext context) { Post post = Post.LoadById(int.Parse(context.requestParts[1])); + post.thread.incrementViewsCounter(); return new XElement[] { new XElement("currentLocation", post.exportToXmlSimpleWithParent(context)), new XElement("posts", post.exportToXmlWithoutThread(context, true)) diff --git a/IISMainHandler/handlers/ThreadHandler.cs b/IISMainHandler/handlers/ThreadHandler.cs index fc31c32..9c256de 100644 --- a/IISMainHandler/handlers/ThreadHandler.cs +++ b/IISMainHandler/handlers/ThreadHandler.cs @@ -51,6 +51,7 @@ namespace FLocal.IISHandler.handlers { } ); IEnumerable posts = thread.getPosts(pageOuter, context); + thread.incrementViewsCounter(); return new XElement[] { new XElement("currentLocation", thread.exportToXmlSimpleWithParent(context)), new XElement("posts", diff --git a/MySQLConnector/ConditionCompiler.cs b/MySQLConnector/ConditionCompiler.cs index 3a639c1..911cc68 100644 --- a/MySQLConnector/ConditionCompiler.cs +++ b/MySQLConnector/ConditionCompiler.cs @@ -41,7 +41,7 @@ namespace FLocal.MySQLConnector { case ComparisonType.NOTEQUAL: return left + " != " + right; default: - throw new NotImplementedException(); + throw new NotSupportedException(); } } @@ -76,7 +76,7 @@ namespace FLocal.MySQLConnector { } else if(condition is MultiValueCondition) { return CompileCondition((MultiValueCondition)condition); } else { - throw new NotImplementedException(); + throw new NotSupportedException(); } } @@ -92,7 +92,7 @@ namespace FLocal.MySQLConnector { case ConditionsJoinType.OR: return string.Join(" OR ", parts.ToArray()); default: - throw new NotImplementedException(); + throw new NotSupportedException(); } } @@ -102,7 +102,7 @@ namespace FLocal.MySQLConnector { } else if(condition is SimpleCondition) { return CompileCondition((SimpleCondition)condition); } else { - throw new NotImplementedException(); + throw new NotSupportedException(); } } @@ -116,7 +116,7 @@ namespace FLocal.MySQLConnector { } else if(condition is EmptyCondition) { return CompileCondition((EmptyCondition)condition); } else { - throw new NotImplementedException(); + throw new NotSupportedException(); } } diff --git a/MySQLConnector/Connection.cs b/MySQLConnector/Connection.cs index df0fdd4..2b856dd 100644 --- a/MySQLConnector/Connection.cs +++ b/MySQLConnector/Connection.cs @@ -194,7 +194,7 @@ namespace FLocal.MySQLConnector { using(DbCommand command = transaction.sqlconnection.CreateCommand()) { command.Transaction = transaction.sqltransaction; command.CommandType = System.Data.CommandType.Text; - command.CommandText = "LOCK TABLES " + table.compile(this.traits); + command.CommandText = "LOCK TABLE " + table.compile(this.traits); command.ExecuteNonQuery(); } } @@ -240,6 +240,7 @@ namespace FLocal.MySQLConnector { foreach(KeyValuePair kvp in paramsholder.data) { command.AddParameter(kvp.Key, kvp.Value); } +// throw new CriticalException(command.CommandText + "; parameters: " + string.Join(", ", (from DbParameter parameter in command.Parameters select parameter.ParameterName + "='" + parameter.Value.ToString() + "'").ToArray())); command.ExecuteNonQuery(); } }