diff --git a/SequelNet.SchemaGenerator.VSIX/SchemaGenerator/InsertMethod.cs b/SequelNet.SchemaGenerator.VSIX/SchemaGenerator/InsertMethod.cs index 8e7194cb..6238772b 100644 --- a/SequelNet.SchemaGenerator.VSIX/SchemaGenerator/InsertMethod.cs +++ b/SequelNet.SchemaGenerator.VSIX/SchemaGenerator/InsertMethod.cs @@ -6,21 +6,12 @@ namespace SequelNet.SchemaGenerator { public partial class GeneratorCore { - private static void WriteInsertMethod(StringBuilder stringBuilder, ScriptContext context) + private static void WriteGetInsertQuery(StringBuilder stringBuilder, ScriptContext context) { - stringBuilder.AppendFormat("public override void Insert(ConnectorBase conn = null, string userName = null){0}{{{0}", "\r\n"); + stringBuilder.AppendFormat("public override Query GetInsertQuery(){0}{{{0}", "\r\n"); bool printExtraNewLine = false; - - if (!context.NoCreatedBy) - { - if (context.Columns.Find((DalColumn c) => c.PropertyName == "CreatedBy") != null) - { - stringBuilder.AppendFormat("CreatedBy = userName;{0}", "\r\n"); - printExtraNewLine = true; - } - } - + if (!context.NoCreatedOn) { if (context.Columns.Find((DalColumn c) => c.PropertyName == "CreatedOn") != null) @@ -39,7 +30,9 @@ private static void WriteInsertMethod(StringBuilder stringBuilder, ScriptContext { stringBuilder.AppendFormat("{1}{0}{0}", "\r\n", context.CustomBeforeInsert); } + stringBuilder.AppendFormat("Query qry = new Query(Schema);{0}", "\r\n"); + foreach (DalColumn dalCol in context.Columns) { if ((dalCol.AutoIncrement && !context.InsertAutoIncrement) || dalCol.NoSave) @@ -79,128 +72,147 @@ private static void WriteInsertMethod(StringBuilder stringBuilder, ScriptContext } } + stringBuilder.AppendFormat("{0}return qry = null;{0}", "\r\n"); + + stringBuilder.AppendFormat("}}{0}}}{0}", "\r\n"); + } + + private static string GetLastInsertValueConvertFormat(ScriptContext context) + { + string valueConvertorFormat = "{0}"; + + DalColumn dalCol = context.Columns.Find( + (DalColumn c) => c.Name == context.SingleColumnPrimaryKeyName + || c.PropertyName == context.SingleColumnPrimaryKeyName + ); + if (dalCol.Type == DalColumnType.TBool) + { + valueConvertorFormat = "Convert.ToBoolean({0})"; + } + else if (dalCol.Type == DalColumnType.TGuid) + { + valueConvertorFormat = "new Guid({0}.ToString())"; + } + else if (dalCol.Type == DalColumnType.TInt) + { + valueConvertorFormat = "Convert.ToInt32({0})"; + } + else if (dalCol.Type == DalColumnType.TInt8) + { + valueConvertorFormat = "Convert.ToSByte({0})"; + } + else if (dalCol.Type == DalColumnType.TInt16) + { + valueConvertorFormat = "Convert.ToInt16({0})"; + } + else if (dalCol.Type == DalColumnType.TInt32) + { + valueConvertorFormat = "Convert.ToInt32({0})"; + } + else if (dalCol.Type == DalColumnType.TInt64) + { + valueConvertorFormat = "Convert.ToInt64({0})"; + } + else if (dalCol.Type == DalColumnType.TUInt8) + { + valueConvertorFormat = "Convert.ToByte({0})"; + } + else if (dalCol.Type == DalColumnType.TUInt16) + { + valueConvertorFormat = "Convert.ToUInt16({0})"; + } + else if (dalCol.Type == DalColumnType.TUInt32) + { + valueConvertorFormat = "Convert.ToUInt32({0})"; + } + else if (dalCol.Type == DalColumnType.TUInt64) + { + valueConvertorFormat = "Convert.ToUInt64({0})"; + } + else if (dalCol.Type == DalColumnType.TDecimal || dalCol.Type == DalColumnType.TMoney) + { + valueConvertorFormat = "Convert.ToDecimal({0})"; + } + else if (dalCol.Type == DalColumnType.TDouble) + { + valueConvertorFormat = "Convert.ToDouble({0})"; + } + else if (dalCol.Type == DalColumnType.TFloat) + { + valueConvertorFormat = "Convert.ToSingle({0})"; + } + else if (dalCol.Type == DalColumnType.TDateTime) + { + valueConvertorFormat = "Convert.ToDateTime({0})"; + } + else if (dalCol.Type == DalColumnType.TDateTimeUtc) + { + valueConvertorFormat = "DateTime.SpecifyKind(Convert.ToDateTime({0}), DateTimeKind.Utc)"; + } + else if (dalCol.Type == DalColumnType.TDateTimeLocal) + { + valueConvertorFormat = "DateTime.SpecifyKind(Convert.ToDateTime({0}), DateTimeKind.Local)"; + } + else if (dalCol.Type == DalColumnType.TJson || + dalCol.Type == DalColumnType.TJsonBinary) + { + valueConvertorFormat = "(string){0}"; + } + else if (dalCol.Type == DalColumnType.TLongText || + dalCol.Type == DalColumnType.TMediumText || + dalCol.Type == DalColumnType.TText || + dalCol.Type == DalColumnType.TString || + dalCol.Type == DalColumnType.TFixedString) + { + valueConvertorFormat = "(string){0}"; + } + else if (dalCol.Type == DalColumnType.TGeometry + || dalCol.Type == DalColumnType.TGeometryCollection + || dalCol.Type == DalColumnType.TPoint + || dalCol.Type == DalColumnType.TLineString + || dalCol.Type == DalColumnType.TPolygon + || dalCol.Type == DalColumnType.TLine + || dalCol.Type == DalColumnType.TCurve + || dalCol.Type == DalColumnType.TSurface + || dalCol.Type == DalColumnType.TLinearRing + || dalCol.Type == DalColumnType.TMultiPoint + || dalCol.Type == DalColumnType.TMultiLineString + || dalCol.Type == DalColumnType.TMultiPolygon + || dalCol.Type == DalColumnType.TMultiCurve + || dalCol.Type == DalColumnType.TMultiSurface + || dalCol.Type == DalColumnType.TGeographic + || dalCol.Type == DalColumnType.TGeographicCollection + || dalCol.Type == DalColumnType.TGeographicPoint + || dalCol.Type == DalColumnType.TGeographicLineString + || dalCol.Type == DalColumnType.TGeographicPolygon + || dalCol.Type == DalColumnType.TGeographicLine + || dalCol.Type == DalColumnType.TGeographicCurve + || dalCol.Type == DalColumnType.TGeographicSurface + || dalCol.Type == DalColumnType.TGeographicLinearRing + || dalCol.Type == DalColumnType.TGeographicMultiPoint + || dalCol.Type == DalColumnType.TGeographicMultiLineString + || dalCol.Type == DalColumnType.TGeographicMultiPolygon + || dalCol.Type == DalColumnType.TGeographicMultiCurve + || dalCol.Type == DalColumnType.TGeographicMultiSurface) + { + valueConvertorFormat = "conn.ReadGeometry({0}) as " + dalCol.ActualType; + } + + return valueConvertorFormat; + } + + private static void WriteInsertMethod(StringBuilder stringBuilder, ScriptContext context) + { + stringBuilder.AppendFormat("public override void Insert(ConnectorBase conn = null){0}{{{0}", "\r\n"); + + stringBuilder.AppendFormat("var qry = GetInsertQuery();{0}", "\r\n"); + stringBuilder.AppendFormat("{0}object lastInsert = null;{0}if (qry.Execute(out lastInsert, conn) > 0){0}{{{0}", "\r\n"); if (!string.IsNullOrEmpty(context.SingleColumnPrimaryKeyName)) { - string valueConvertorFormat = "{0}"; - - DalColumn dalCol = context.Columns.Find( - (DalColumn c) => c.Name == context.SingleColumnPrimaryKeyName - || c.PropertyName == context.SingleColumnPrimaryKeyName - ); - if (dalCol.Type == DalColumnType.TBool) - { - valueConvertorFormat = "Convert.ToBoolean({0})"; - } - else if (dalCol.Type == DalColumnType.TGuid) - { - valueConvertorFormat = "new Guid({0}.ToString())"; - } - else if (dalCol.Type == DalColumnType.TInt) - { - valueConvertorFormat = "Convert.ToInt32({0})"; - } - else if (dalCol.Type == DalColumnType.TInt8) - { - valueConvertorFormat = "Convert.ToSByte({0})"; - } - else if (dalCol.Type == DalColumnType.TInt16) - { - valueConvertorFormat = "Convert.ToInt16({0})"; - } - else if (dalCol.Type == DalColumnType.TInt32) - { - valueConvertorFormat = "Convert.ToInt32({0})"; - } - else if (dalCol.Type == DalColumnType.TInt64) - { - valueConvertorFormat = "Convert.ToInt64({0})"; - } - else if (dalCol.Type == DalColumnType.TUInt8) - { - valueConvertorFormat = "Convert.ToByte({0})"; - } - else if (dalCol.Type == DalColumnType.TUInt16) - { - valueConvertorFormat = "Convert.ToUInt16({0})"; - } - else if (dalCol.Type == DalColumnType.TUInt32) - { - valueConvertorFormat = "Convert.ToUInt32({0})"; - } - else if (dalCol.Type == DalColumnType.TUInt64) - { - valueConvertorFormat = "Convert.ToUInt64({0})"; - } - else if (dalCol.Type == DalColumnType.TDecimal || dalCol.Type == DalColumnType.TMoney) - { - valueConvertorFormat = "Convert.ToDecimal({0})"; - } - else if (dalCol.Type == DalColumnType.TDouble) - { - valueConvertorFormat = "Convert.ToDouble({0})"; - } - else if (dalCol.Type == DalColumnType.TFloat) - { - valueConvertorFormat = "Convert.ToSingle({0})"; - } - else if (dalCol.Type == DalColumnType.TDateTime) - { - valueConvertorFormat = "Convert.ToDateTime({0})"; - } - else if (dalCol.Type == DalColumnType.TDateTimeUtc) - { - valueConvertorFormat = "DateTime.SpecifyKind(Convert.ToDateTime({0}), DateTimeKind.Utc)"; - } - else if (dalCol.Type == DalColumnType.TDateTimeLocal) - { - valueConvertorFormat = "DateTime.SpecifyKind(Convert.ToDateTime({0}), DateTimeKind.Local)"; - } - else if (dalCol.Type == DalColumnType.TJson || - dalCol.Type == DalColumnType.TJsonBinary) - { - valueConvertorFormat = "(string){0}"; - } - else if (dalCol.Type == DalColumnType.TLongText || - dalCol.Type == DalColumnType.TMediumText || - dalCol.Type == DalColumnType.TText || - dalCol.Type == DalColumnType.TString || - dalCol.Type == DalColumnType.TFixedString) - { - valueConvertorFormat = "(string){0}"; - } - else if (dalCol.Type == DalColumnType.TGeometry - || dalCol.Type == DalColumnType.TGeometryCollection - || dalCol.Type == DalColumnType.TPoint - || dalCol.Type == DalColumnType.TLineString - || dalCol.Type == DalColumnType.TPolygon - || dalCol.Type == DalColumnType.TLine - || dalCol.Type == DalColumnType.TCurve - || dalCol.Type == DalColumnType.TSurface - || dalCol.Type == DalColumnType.TLinearRing - || dalCol.Type == DalColumnType.TMultiPoint - || dalCol.Type == DalColumnType.TMultiLineString - || dalCol.Type == DalColumnType.TMultiPolygon - || dalCol.Type == DalColumnType.TMultiCurve - || dalCol.Type == DalColumnType.TMultiSurface - || dalCol.Type == DalColumnType.TGeographic - || dalCol.Type == DalColumnType.TGeographicCollection - || dalCol.Type == DalColumnType.TGeographicPoint - || dalCol.Type == DalColumnType.TGeographicLineString - || dalCol.Type == DalColumnType.TGeographicPolygon - || dalCol.Type == DalColumnType.TGeographicLine - || dalCol.Type == DalColumnType.TGeographicCurve - || dalCol.Type == DalColumnType.TGeographicSurface - || dalCol.Type == DalColumnType.TGeographicLinearRing - || dalCol.Type == DalColumnType.TGeographicMultiPoint - || dalCol.Type == DalColumnType.TGeographicMultiLineString - || dalCol.Type == DalColumnType.TGeographicMultiPolygon - || dalCol.Type == DalColumnType.TGeographicMultiCurve - || dalCol.Type == DalColumnType.TGeographicMultiSurface) - { - valueConvertorFormat = "conn.ReadGeometry({0}) as " + dalCol.ActualType; - } - stringBuilder.AppendFormat("{1} = {2};{0}", "\r\n", context.SingleColumnPrimaryKeyName, string.Format(valueConvertorFormat, "(lastInsert)")); + stringBuilder.AppendFormat("{1} = {2};{0}", "\r\n", + context.SingleColumnPrimaryKeyName, + string.Format(GetLastInsertValueConvertFormat(context), "(lastInsert)")); } stringBuilder.AppendFormat("MarkOld();{0}", "\r\n"); @@ -212,5 +224,32 @@ private static void WriteInsertMethod(StringBuilder stringBuilder, ScriptContext stringBuilder.AppendFormat("}}{0}}}{0}", "\r\n"); } - } + + private static void WriteInsertAsyncMethod(StringBuilder stringBuilder, ScriptContext context) + { + stringBuilder.AppendFormat("public override Task InsertAsync(ConnectorBase connection = null, CancellationToken? cancellationToken = null){0}{{{0}", "\r\n"); + + stringBuilder.AppendFormat("var qry = GetInsertQuery();{0}", "\r\n"); + + stringBuilder.AppendFormat("{0}var results = qry.ExecuteWithLastInsertIdAsync(conn, cancellationToken);{0}", "\r\n"); + stringBuilder.AppendFormat("{0}if (results.updates > 0) {{{0}", "\r\n"); + if (!string.IsNullOrEmpty(context.SingleColumnPrimaryKeyName)) + { + stringBuilder.AppendFormat("{1} = {2};{0}", "\r\n", + context.SingleColumnPrimaryKeyName, + string.Format(GetLastInsertValueConvertFormat(context), "(results.lastInsertId)")); + } + + stringBuilder.AppendFormat("MarkOld();{0}", "\r\n"); + + if (context.AtomicUpdates) + { + stringBuilder.AppendFormat("MarkAllColumnsNotMutated();{0}", "\r\n"); + } + + stringBuilder.AppendFormat("}}{0}", "\r\n"); // if + + stringBuilder.AppendFormat("}}{0}", "\r\n"); // function + } + } } \ No newline at end of file diff --git a/SequelNet.SchemaGenerator.VSIX/SchemaGenerator/Parse.cs b/SequelNet.SchemaGenerator.VSIX/SchemaGenerator/Parse.cs index b814dec2..6a1194c1 100644 --- a/SequelNet.SchemaGenerator.VSIX/SchemaGenerator/Parse.cs +++ b/SequelNet.SchemaGenerator.VSIX/SchemaGenerator/Parse.cs @@ -212,18 +212,10 @@ private static void ParseScript(ScriptContext context, string[] scriptLines) { context.InsertAutoIncrement = true; } - else if (currentLineTrimmed.StartsWith("@NoCreatedBy", StringComparison.OrdinalIgnoreCase)) - { - context.NoCreatedBy = true; - } else if (currentLineTrimmed.StartsWith("@NoCreatedOn", StringComparison.OrdinalIgnoreCase)) { context.NoCreatedOn = true; } - else if (currentLineTrimmed.StartsWith("@NoModifiedBy", StringComparison.OrdinalIgnoreCase)) - { - context.NoModifiedBy = true; - } else if (currentLineTrimmed.StartsWith("@NoModifiedOn", StringComparison.OrdinalIgnoreCase)) { context.NoModifiedOn = true; diff --git a/SequelNet.SchemaGenerator.VSIX/SchemaGenerator/SchemaGenerator.cs b/SequelNet.SchemaGenerator.VSIX/SchemaGenerator/SchemaGenerator.cs index b0fb6e1d..bd211dee 100644 --- a/SequelNet.SchemaGenerator.VSIX/SchemaGenerator/SchemaGenerator.cs +++ b/SequelNet.SchemaGenerator.VSIX/SchemaGenerator/SchemaGenerator.cs @@ -119,10 +119,18 @@ private static void WriteRecord(StringBuilder stringBuilder, ScriptContext conte stringBuilder.AppendFormat("public override object GetPrimaryKeyValue(){0}{{{0}return {1};{0}}}{0}{0}", "\r\n", string.IsNullOrEmpty(context.SingleColumnPrimaryKeyName) ? "null" : context.SingleColumnPrimaryKeyName); + WriteGetInsertQuery(stringBuilder, context); + stringBuilder.Append("\r\n"); + WriteGetUpdateQuery(stringBuilder, context); + stringBuilder.Append("\r\n"); WriteInsertMethod(stringBuilder, context); stringBuilder.Append("\r\n"); + WriteInsertAsyncMethod(stringBuilder, context); + stringBuilder.Append("\r\n"); WriteUpdateMethod(stringBuilder, context); stringBuilder.Append("\r\n"); + WriteUpdateAsyncMethod(stringBuilder, context); + stringBuilder.Append("\r\n"); WriteReadMethod(stringBuilder, context); stringBuilder.AppendFormat("{0}#endregion{0}{0}", "\r\n"); diff --git a/SequelNet.SchemaGenerator.VSIX/SchemaGenerator/ScriptContext.cs b/SequelNet.SchemaGenerator.VSIX/SchemaGenerator/ScriptContext.cs index 4234e63a..50ddd240 100644 --- a/SequelNet.SchemaGenerator.VSIX/SchemaGenerator/ScriptContext.cs +++ b/SequelNet.SchemaGenerator.VSIX/SchemaGenerator/ScriptContext.cs @@ -21,9 +21,7 @@ public class ScriptContext public bool AtomicUpdates = false; public bool SnakeColumnNames = false; public bool InsertAutoIncrement = false; - public bool NoCreatedBy = false; public bool NoCreatedOn = false; - public bool NoModifiedBy = false; public bool NoModifiedOn = false; public string SingleColumnPrimaryKeyName = null; diff --git a/SequelNet.SchemaGenerator.VSIX/SchemaGenerator/UpdateMethod.cs b/SequelNet.SchemaGenerator.VSIX/SchemaGenerator/UpdateMethod.cs index 99ad6fc8..432b45a3 100644 --- a/SequelNet.SchemaGenerator.VSIX/SchemaGenerator/UpdateMethod.cs +++ b/SequelNet.SchemaGenerator.VSIX/SchemaGenerator/UpdateMethod.cs @@ -6,26 +6,17 @@ namespace SequelNet.SchemaGenerator { public partial class GeneratorCore { - private static void WriteUpdateMethod(StringBuilder stringBuilder, ScriptContext context) + private static void WriteGetUpdateQuery(StringBuilder stringBuilder, ScriptContext context) { - stringBuilder.AppendFormat("public override void Update(ConnectorBase conn = null, string userName = null){0}{{{0}", "\r\n"); + stringBuilder.AppendFormat("public override Query GetUpdateQuery(){0}{{{0}", "\r\n"); - bool hasModifiedBy = context.Columns.Find((DalColumn c) => c.PropertyName == "ModifiedBy") != null; bool hasModifiedOn = context.Columns.Find((DalColumn c) => c.PropertyName == "ModifiedOn") != null; - if (context.AtomicUpdates && (hasModifiedBy || hasModifiedOn)) + if (context.AtomicUpdates && (hasModifiedOn)) { stringBuilder.AppendFormat(@"if (HasMutatedColumns()){0}{{{0}", "\r\n"); } - if (!context.NoModifiedBy) - { - if (context.Columns.Find((DalColumn c) => c.PropertyName == "ModifiedBy") != null) - { - stringBuilder.AppendFormat("ModifiedBy = userName;{0}", "\r\n"); - } - } - if (!context.NoModifiedOn) { if (context.Columns.Find((DalColumn c) => c.PropertyName == "ModifiedOn") != null) @@ -34,12 +25,12 @@ private static void WriteUpdateMethod(StringBuilder stringBuilder, ScriptContext } } - if (context.AtomicUpdates && (hasModifiedBy || hasModifiedOn)) + if (context.AtomicUpdates && (hasModifiedOn)) { stringBuilder.AppendFormat(@"}}{0}", "\r\n"); } - if (hasModifiedBy || hasModifiedOn) + if (hasModifiedOn) { stringBuilder.Append("\r\n"); } @@ -80,13 +71,46 @@ private static void WriteUpdateMethod(StringBuilder stringBuilder, ScriptContext isFirst = false; } - stringBuilder.AppendFormat("{0}", "\r\n"); + stringBuilder.AppendFormat("{0}return qry = null;{0}", "\r\n"); + + stringBuilder.AppendFormat("}}{0}}}{0}", "\r\n"); + } + + private static void WriteUpdateMethod(StringBuilder stringBuilder, ScriptContext context) + { + stringBuilder.AppendFormat("public override void Update(ConnectorBase conn = null){0}{{{0}", "\r\n"); + + stringBuilder.AppendFormat("var qry = GetUpdateQuery();{0}{0}", "\r\n"); if (context.AtomicUpdates) { stringBuilder.AppendFormat("if (qry.HasInsertsOrUpdates){0}{{{0}", "\r\n"); } + stringBuilder.AppendFormat("qry.Execute(conn);{0}", "\r\n"); + + if (context.AtomicUpdates) + { + stringBuilder.AppendFormat("}}{0}", "\r\n"); + stringBuilder.AppendFormat("{0}MarkAllColumnsNotMutated();{0}", "\r\n"); + } + + stringBuilder.AppendFormat("}}{0}", "\r\n"); + } + + private static void WriteUpdateAsyncMethod(StringBuilder stringBuilder, ScriptContext context) + { + stringBuilder.AppendFormat("public override Task UpdateAsync(ConnectorBase connection = null, CancellationToken? cancellationToken = null){0}{{{0}", "\r\n"); + + stringBuilder.AppendFormat("var qry = GetUpdateQuery();{0}{0}", "\r\n"); + + if (context.AtomicUpdates) + { + stringBuilder.AppendFormat("if (qry.HasInsertsOrUpdates){0}{{{0}", "\r\n"); + } + + stringBuilder.AppendFormat("qry.ExecuteAsync(conn, cancellationToken);{0}", "\r\n"); + if (context.AtomicUpdates) { stringBuilder.AppendFormat("}}{0}", "\r\n"); @@ -95,5 +119,5 @@ private static void WriteUpdateMethod(StringBuilder stringBuilder, ScriptContext stringBuilder.AppendFormat("}}{0}", "\r\n"); } - } + } } \ No newline at end of file diff --git a/SequelNet/Sql/Query/Executes.cs b/SequelNet/Sql/Query/Executes.cs index 8182c0fb..f4b0c56b 100644 --- a/SequelNet/Sql/Query/Executes.cs +++ b/SequelNet/Sql/Query/Executes.cs @@ -232,6 +232,7 @@ public int Execute(out object lastInsertId, ConnectorBase connection = null) /// An existing connection to use. /// Where to put the last inserted ROWID /// Number of affected rows + [Obsolete] public int Execute(ConnectorBase connection, out object lastInsertId) { return Execute(out lastInsertId, connection); diff --git a/SequelNet/Sql/RecordEntity/AbstractRecord.cs b/SequelNet/Sql/RecordEntity/AbstractRecord.cs index 1aaa46ac..0846662b 100644 --- a/SequelNet/Sql/RecordEntity/AbstractRecord.cs +++ b/SequelNet/Sql/RecordEntity/AbstractRecord.cs @@ -4,6 +4,8 @@ using SequelNet.Connector; using System.Collections; using System.Reflection; +using System.Threading; +using System.Threading.Tasks; namespace SequelNet { @@ -22,9 +24,7 @@ public abstract class AbstractRecord : IRecord private static bool __FLAGS_RETRIEVED = false; private static bool __HAS_DELETED = false; private static bool __HAS_IS_DELETED = false; - private static bool __HAS_CREATED_BY = false; private static bool __HAS_CREATED_ON= false; - private static bool __HAS_MODIFIED_BY = false; private static bool __HAS_MODIFIED_ON = false; #endregion @@ -161,9 +161,7 @@ private static void RetrieveFlags() { __HAS_DELETED = Schema.Columns.Find(@"Deleted") != null; __HAS_IS_DELETED = Schema.Columns.Find(@"IsDeleted") != null; - __HAS_CREATED_BY = Schema.Columns.Find(@"CreatedBy") != null; __HAS_CREATED_ON = Schema.Columns.Find(@"CreatedOn") != null; - __HAS_MODIFIED_BY = Schema.Columns.Find(@"ModifiedBy") != null; __HAS_MODIFIED_ON = Schema.Columns.Find(@"ModifiedOn") != null; __FLAGS_RETRIEVED = true; } @@ -232,16 +230,13 @@ public void MarkNew() #region Virtual Read/Write Actions - public virtual void Insert(ConnectorBase connection = null, string userName = null) + public virtual Query GetInsertQuery() { if (!__FLAGS_RETRIEVED) - { RetrieveFlags(); - } + if (__CLASS_TYPE == null) - { __CLASS_TYPE = this.GetType(); - } var qry = new Query(Schema); @@ -249,73 +244,122 @@ public virtual void Insert(ConnectorBase connection = null, string userName = nu { var propInfo = __CLASS_TYPE.GetProperty(column.Name); - if (propInfo == null) + if (propInfo == null) propInfo = __CLASS_TYPE.GetProperty(column.Name + @"X"); if (propInfo != null) qry.Insert(column.Name, propInfo.GetValue(this, null)); } - if (__HAS_CREATED_BY && userName != null) - { - qry.Insert(@"CreatedBy", userName); - } - if (__HAS_CREATED_ON) { qry.Insert(@"CreatedOn", DateTime.UtcNow); } - qry.Execute(connection); - - _NewRecord = false; - MarkAllColumnsNotMutated(); + return qry; } - public virtual void Update(ConnectorBase connection = null, string userName = null) + public virtual Query GetUpdateQuery() { if (!__FLAGS_RETRIEVED) - { RetrieveFlags(); - } + if (__CLASS_TYPE == null) - { __CLASS_TYPE = this.GetType(); - } object primaryKey = SchemaPrimaryKeyName; bool isPrimaryKeyNullOrString = primaryKey == null || primaryKey is string; var qry = new Query(Schema); - foreach (var Column in Schema.Columns) + foreach (var column in Schema.Columns) { - if ((isPrimaryKeyNullOrString && Column.Name == (string)primaryKey) || - (!isPrimaryKeyNullOrString && StringArrayContains((string[])primaryKey, Column.Name))) continue; + if ((isPrimaryKeyNullOrString && column.Name == (string)primaryKey) || + (!isPrimaryKeyNullOrString && StringArrayContains((string[])primaryKey, column.Name))) continue; - var propInfo = __CLASS_TYPE.GetProperty(Column.Name); - if (propInfo == null) propInfo = __CLASS_TYPE.GetProperty(Column.Name + @"X"); + var propInfo = __CLASS_TYPE.GetProperty(column.Name); + if (propInfo == null) propInfo = __CLASS_TYPE.GetProperty(column.Name + @"X"); if (propInfo != null) { - if (_AtomicUpdates && !IsColumnMutated(Column.Name)) continue; + if (_AtomicUpdates && !IsColumnMutated(column.Name)) continue; - qry.Update(Column.Name, propInfo.GetValue(this, null)); + qry.Update(column.Name, propInfo.GetValue(this, null)); } } if (!_AtomicUpdates || qry.HasInsertsOrUpdates) { - if (__HAS_MODIFIED_BY && userName != null) + if (__HAS_MODIFIED_ON) { - qry.Update(@"ModifiedBy", userName); + qry.Update(@"ModifiedOn", DateTime.UtcNow); } + } - if (__HAS_MODIFIED_ON) + return qry; + } + + public virtual void Insert(ConnectorBase connection = null) + { + var qry = GetInsertQuery(); + + if (__PRIMARY_KEY_MULTI) + { + qry.Execute(connection); + } + else + { + if (qry.Execute(out var lastInsertId, connection) > 0) { - qry.Update(@"ModifiedOn", DateTime.UtcNow); + if (__CLASS_TYPE == null) + __CLASS_TYPE = this.GetType(); + + var propInfo = __CLASS_TYPE.GetProperty(SchemaPrimaryKeyName as string); + if (propInfo == null) propInfo = __CLASS_TYPE.GetProperty(SchemaPrimaryKeyName as string + @"X"); + if (propInfo != null) + { + propInfo.SetValue(this, Convert.ChangeType(lastInsertId, FindColumnType(SchemaPrimaryKeyName as string)), null); + } } } + _NewRecord = false; + MarkAllColumnsNotMutated(); + } + + public virtual async Task InsertAsync(ConnectorBase connection = null, CancellationToken? cancellationToken = null) + { + var qry = GetInsertQuery(); + + if (__PRIMARY_KEY_MULTI) + { + await qry.ExecuteAsync(connection, cancellationToken); + } + else + { + var results = await qry.ExecuteWithLastInsertIdAsync(connection, cancellationToken); + + if (results.updates > 0) + { + if (__CLASS_TYPE == null) + __CLASS_TYPE = this.GetType(); + + var propInfo = __CLASS_TYPE.GetProperty(SchemaPrimaryKeyName as string); + if (propInfo == null) propInfo = __CLASS_TYPE.GetProperty(SchemaPrimaryKeyName as string + @"X"); + if (propInfo != null) + { + propInfo.SetValue(this, Convert.ChangeType(results.lastInsertId, FindColumnType(SchemaPrimaryKeyName as string)), null); + } + } + } + + _NewRecord = false; + MarkAllColumnsNotMutated(); + } + + public virtual void Update(ConnectorBase connection = null) + { + var qry = GetUpdateQuery(); + if (qry.HasInsertsOrUpdates) { qry.Execute(connection); @@ -324,21 +368,31 @@ public virtual void Update(ConnectorBase connection = null, string userName = nu MarkAllColumnsNotMutated(); } + public virtual async Task UpdateAsync(ConnectorBase connection = null, CancellationToken? cancellationToken = null) + { + var qry = GetUpdateQuery(); + + if (qry.HasInsertsOrUpdates) + { + await qry.ExecuteAsync(connection, cancellationToken); + } + + MarkAllColumnsNotMutated(); + } + public virtual void Read(DataReader reader) { if (__CLASS_TYPE == null) - { __CLASS_TYPE = this.GetType(); - } PropertyInfo propInfo; - foreach (var Column in Schema.Columns) + foreach (var column in Schema.Columns) { - propInfo = __CLASS_TYPE.GetProperty(Column.Name); - if (propInfo == null) propInfo = __CLASS_TYPE.GetProperty(Column.Name + @"X"); + propInfo = __CLASS_TYPE.GetProperty(column.Name); + if (propInfo == null) propInfo = __CLASS_TYPE.GetProperty(column.Name + @"X"); if (propInfo != null) { - propInfo.SetValue(this, Convert.ChangeType(reader[Column.Name], Column.Type), null); + propInfo.SetValue(this, Convert.ChangeType(reader[column.Name], column.Type), null); } } @@ -346,27 +400,39 @@ public virtual void Read(DataReader reader) MarkAllColumnsNotMutated(); } - public virtual void Save(string userName = null) + public virtual void Save(ConnectorBase connection = null) { if (_NewRecord) { - Insert(null, userName); + Insert(connection); } else { - Update(null, userName); + Update(connection); } } - public virtual void Save(ConnectorBase connection, string userName = null) + public virtual Task SaveAsync(ConnectorBase connection = null, CancellationToken? cancellationToken = null) { if (_NewRecord) { - Insert(connection, userName); + return InsertAsync(connection, cancellationToken); } else { - Update(connection, userName); + return UpdateAsync(connection, cancellationToken); + } + } + + public Task SaveAsync(CancellationToken cancellationToken) + { + if (_NewRecord) + { + return InsertAsync(null, cancellationToken); + } + else + { + return UpdateAsync(null, cancellationToken); } } @@ -377,7 +443,6 @@ public virtual void Save(ConnectorBase connection, string userName = null) /// /// Deletes a record from the db, by matching the Primary Key to . /// If the table has a Deleted or IsDeleted column, it will be marked instead of actually deleted. - /// If the table has a ModifiedBy column, it will be updated with the current identified Username. /// If the table has a ModifiedOn column, it will be updated with the current UTC date/time. /// /// The columns' values to match. Could be a String or an IEnumerable of strings. Must match the Primary Key. @@ -387,13 +452,28 @@ public static int Delete(object primaryKeyValue, ConnectorBase connection = null { object columnName = SchemaPrimaryKeyName; if (columnName == null) return 0; - return DeleteByParameter(columnName, primaryKeyValue, null, connection); + return DeleteByParameter(columnName, primaryKeyValue, connection); + } + + /// + /// Deletes a record from the db, by matching the Primary Key to . + /// If the table has a Deleted or IsDeleted column, it will be marked instead of actually deleted. + /// If the table has a ModifiedOn column, it will be updated with the current UTC date/time. + /// + /// The columns' values to match. Could be a String or an IEnumerable of strings. Must match the Primary Key. + /// An optional db connection to use when executing the query. + /// Cancellation token. + /// Number of affected rows. + public static Task DeleteAsync(object primaryKeyValue, ConnectorBase connection = null, CancellationToken? cancellationToken = null) + { + object columnName = SchemaPrimaryKeyName; + if (columnName == null) return Task.FromResult(0); + return DeleteByParameterAsync(columnName, primaryKeyValue, connection, cancellationToken); } /// /// Deletes a record from the db, by matching to . /// If the table has a Deleted or IsDeleted column, it will be marked instead of actually deleted. - /// If the table has a ModifiedBy column, it will be updated with the current identified Username. /// If the table has a ModifiedOn column, it will be updated with the current UTC date/time. /// /// The column's name to Where. Could be a String or an IEnumerable of strings. @@ -402,36 +482,34 @@ public static int Delete(object primaryKeyValue, ConnectorBase connection = null /// Number of affected rows. public static int Delete(string columnName, object value, ConnectorBase connection = null) { - return DeleteByParameter(columnName, value, null, connection); + return DeleteByParameter(columnName, value, connection); } /// /// Deletes a record from the db, by matching to . /// If the table has a Deleted or IsDeleted column, it will be marked instead of actually deleted. - /// If the table has a ModifiedBy column, it will be updated with or the current identified Username. /// If the table has a ModifiedOn column, it will be updated with the current UTC date/time. /// /// The column's name to Where. Could be a String or an IEnumerable of strings. /// The columns' values to match. Could be a String or an IEnumerable of strings. Must match the - /// An optional username to use if updating a ModifiedBy column. /// An optional db connection to use when executing the query. + /// Cancellation token. /// Number of affected rows. - public static int Delete(string columnName, object value, string userName, ConnectorBase connection = null) + public static Task DeleteAsync(string columnName, object value, ConnectorBase connection = null, CancellationToken? cancellationToken = null) { - return DeleteByParameter(columnName, value, userName, connection); + return DeleteByParameterAsync(columnName, value, connection, cancellationToken); } /// /// Deletes a record from the db, by matching to . /// If the table has a Deleted or IsDeleted column, it will be marked instead of actually deleted. - /// If the table has a ModifiedBy column, it will be updated with the current identified Username. /// If the table has a ModifiedOn column, it will be updated with the current UTC date/time. /// /// The column's name to Where. Could be a String or an IEnumerable of strings. /// The columns' values to match. Could be a String or an IEnumerable of strings. Must match the /// An optional db connection to use when executing the query. /// Number of affected rows. - private static int DeleteByParameter(object columnName, object value, string userName, ConnectorBase connection) + private static int DeleteByParameter(object columnName, object value, ConnectorBase connection) { if (!__FLAGS_RETRIEVED) { @@ -444,7 +522,6 @@ private static int DeleteByParameter(object columnName, object value, string use if (__HAS_DELETED) qry.Update(@"Deleted", true); if (__HAS_IS_DELETED) qry.Update(@"IsDeleted", true); - if (__HAS_MODIFIED_BY && !string.IsNullOrEmpty(userName)) qry.Update(@"ModifiedBy", userName); if (__HAS_MODIFIED_ON) qry.Update(@"ModifiedOn", DateTime.UtcNow); if (columnName is ICollection) @@ -468,6 +545,52 @@ private static int DeleteByParameter(object columnName, object value, string use return DestroyByParameter(columnName, value, connection); } + /// + /// Deletes a record from the db, by matching to . + /// If the table has a Deleted or IsDeleted column, it will be marked instead of actually deleted. + /// If the table has a ModifiedOn column, it will be updated with the current UTC date/time. + /// + /// The column's name to Where. Could be a String or an IEnumerable of strings. + /// The columns' values to match. Could be a String or an IEnumerable of strings. Must match the + /// An optional db connection to use when executing the query. + /// Cancellation token. + /// Number of affected rows. + private static Task DeleteByParameterAsync(object columnName, object value, ConnectorBase connection, CancellationToken? cancellationToken = null) + { + if (!__FLAGS_RETRIEVED) + { + RetrieveFlags(); + } + + if (__HAS_DELETED || __HAS_IS_DELETED) + { + Query qry = new Query(Schema); + + if (__HAS_DELETED) qry.Update(@"Deleted", true); + if (__HAS_IS_DELETED) qry.Update(@"IsDeleted", true); + if (__HAS_MODIFIED_ON) qry.Update(@"ModifiedOn", DateTime.UtcNow); + + if (columnName is ICollection) + { + if (!(value is ICollection)) return Task.FromResult(0); + + IEnumerator keyEnumerator = ((IEnumerable)columnName).GetEnumerator(); + IEnumerator valueEnumerator = ((IEnumerable)value).GetEnumerator(); + + while (keyEnumerator.MoveNext() && valueEnumerator.MoveNext()) + { + qry.AND((string)keyEnumerator.Current, valueEnumerator.Current); + } + } + else + { + qry.Where((string)columnName, value); + } + return qry.ExecuteNonQueryAsync(connection, cancellationToken); + } + return DestroyByParameterAsync(columnName, value, connection, cancellationToken); + } + /// /// Deletes a record from the db, by matching the Primary Key to . /// @@ -481,6 +604,20 @@ public static int Destroy(object primaryKeyValue, ConnectorBase connection = nul return DestroyByParameter(columnName, primaryKeyValue, connection); } + /// + /// Deletes a record from the db, by matching the Primary Key to . + /// + /// The columns' values to match. Could be a String or an IEnumerable of strings. Must match the Primary Key. + /// An optional db connection to use when executing the query. + /// Cancellation token. + /// Number of affected rows. + public static Task DestroyAsync(object primaryKeyValue, ConnectorBase connection = null, CancellationToken? cancellationToken = null) + { + object columnName = SchemaPrimaryKeyName; + if (columnName == null) return Task.FromResult(0); + return DestroyByParameterAsync(columnName, primaryKeyValue, connection, cancellationToken); + } + /// /// Deletes a record from the db, by matching to . /// @@ -493,6 +630,19 @@ public static int Destroy(string columnName, object value, ConnectorBase connect return DestroyByParameter(columnName, value, connection); } + /// + /// Deletes a record from the db, by matching to . + /// + /// The column's name to Where. Could be a String or an IEnumerable of strings. + /// The columns' values to match. Could be a String or an IEnumerable of strings. Must match the + /// An optional db connection to use when executing the query. + /// Cancellation token. + /// Number of affected rows. + public static Task DestroyAsync(string columnName, object value, ConnectorBase connection = null, CancellationToken? cancellationToken = null) + { + return DestroyByParameterAsync(columnName, value, connection, cancellationToken); + } + /// /// Deletes a record from the db, by matching to . /// @@ -524,6 +674,38 @@ private static int DestroyByParameter(object columnName, object value, Connector return qry.ExecuteNonQuery(connection); } + /// + /// Deletes a record from the db, by matching to . + /// + /// The column's name to Where. Could be a String or an IEnumerable of strings. + /// The columns' values to match. Could be a String or an IEnumerable of strings. Must match the + /// An optional db connection to use when executing the query. + /// Cancellation token. + /// Number of affected rows. + private static Task DestroyByParameterAsync(object columnName, object value, ConnectorBase connection, CancellationToken? cancellationToken = null) + { + Query qry = new Query(Schema).Delete(); + + if (columnName is ICollection) + { + if (!(value is ICollection)) return Task.FromResult(0); + + IEnumerator keyEnumerator = ((IEnumerable)columnName).GetEnumerator(); + IEnumerator valueEnumerator = ((IEnumerable)value).GetEnumerator(); + + while (keyEnumerator.MoveNext() && valueEnumerator.MoveNext()) + { + qry.AND((string)keyEnumerator.Current, valueEnumerator.Current); + } + } + else + { + qry.Where((string)columnName, value); + } + + return qry.ExecuteNonQueryAsync(connection, cancellationToken); + } + #endregion #region Column utilities @@ -591,6 +773,43 @@ public static T FetchByID(object primaryKeyValue, ConnectorBase connection = nul return null; } + /// + /// Fetches a record from the db, by matching the Primary Key to . + /// + /// The columns' values to match. Could be a String or an IEnumerable of strings. Must match the Primary Key. + /// An optional db connection to use when executing the query. + /// Cancellation token. + /// A record (marked as "old") or null. + public static async Task FetchByIdAsync(object primaryKeyValue, ConnectorBase connection = null, CancellationToken? cancellationToken = null) + { + Query qry = new Query(Schema); + + object primaryKey = SchemaPrimaryKeyName; + if (__PRIMARY_KEY_MULTI) + { + if (!(primaryKeyValue is ICollection)) return null; + + IEnumerator keyEnumerator = ((IEnumerable)primaryKey).GetEnumerator(); + IEnumerator valueEnumerator = ((IEnumerable)primaryKeyValue).GetEnumerator(); + + while (keyEnumerator.MoveNext() && valueEnumerator.MoveNext()) + { + qry.AND((string)keyEnumerator.Current, valueEnumerator.Current); + } + } + else + { + qry.Where((string)primaryKey, primaryKeyValue); + } + + using (var reader = await qry.ExecuteReaderAsync(connection, cancellationToken)) + { + if (await reader.ReadAsync(cancellationToken)) + return FromReader(reader); + } + return null; + } + /// /// Loads a record from the db, by matching the Primary Key to . /// If the record was loaded, it will be marked as an "old" record. @@ -601,7 +820,19 @@ public void LoadByKey(object primaryKeyValue, ConnectorBase connection = null) { LoadByParam(SchemaPrimaryKeyName, primaryKeyValue, connection); } - + + /// + /// Loads a record from the db, by matching the Primary Key to . + /// If the record was loaded, it will be marked as an "old" record. + /// + /// The columns' values to match. Could be a String or an IEnumerable of strings. Must match the Primary Key. + /// An optional db connection to use when executing the query. + /// Cancellation token. + public Task LoadByKeyAsync(object primaryKeyValue, ConnectorBase connection = null, CancellationToken? cancellationToken = null) + { + return LoadByParamAsync(SchemaPrimaryKeyName, primaryKeyValue, connection, cancellationToken); + } + /// /// Loads a record from the db, by matching to . /// If the record was loaded, it will be marked as an "old" record. @@ -630,7 +861,7 @@ public void LoadByParam(object columnName, object value, ConnectorBase connectio qry.Where((string)columnName, value); } - using (DataReader reader = qry.ExecuteReader(connection)) + using (var reader = qry.ExecuteReader(connection)) { if (reader.Read()) { @@ -640,6 +871,45 @@ public void LoadByParam(object columnName, object value, ConnectorBase connectio } } + /// + /// Loads a record from the db, by matching to . + /// If the record was loaded, it will be marked as an "old" record. + /// + /// The column's name to Where. Could be a String or an IEnumerable of strings. + /// The columns' values to match. Could be a String or an IEnumerable of strings. Must match the + /// An optional db connection to use when executing the query. + public async Task LoadByParamAsync(object columnName, object value, ConnectorBase connection = null, CancellationToken? cancellationToken = null) + { + Query qry = new Query(Schema); + + if (columnName is ICollection) + { + if (!(value is ICollection)) + return; + + IEnumerator keyEnumerator = ((IEnumerable)columnName).GetEnumerator(); + IEnumerator valueEnumerator = ((IEnumerable)value).GetEnumerator(); + + while (keyEnumerator.MoveNext() && valueEnumerator.MoveNext()) + { + qry.AND((string)keyEnumerator.Current, valueEnumerator.Current); + } + } + else + { + qry.Where((string)columnName, value); + } + + using (var reader = await qry.ExecuteReaderAsync(connection, cancellationToken)) + { + if (await reader.ReadAsync(cancellationToken)) + { + Read(reader); + MarkOld(); + } + } + } + /// /// Creates a new instance of this record, and loads it from the . /// Will me marked as "old". diff --git a/SequelNet/Sql/RecordEntity/AbstractRecordList.cs b/SequelNet/Sql/RecordEntity/AbstractRecordList.cs index c2a28bf4..eef04338 100644 --- a/SequelNet/Sql/RecordEntity/AbstractRecordList.cs +++ b/SequelNet/Sql/RecordEntity/AbstractRecordList.cs @@ -12,17 +12,44 @@ public abstract class AbstractRecordList where TItemType : AbstractRecord, new() where TListType : AbstractRecordList, new() { - public virtual void SaveAll(ConnectorBase conn) + public virtual void SaveAll(ConnectorBase conn = null, bool withTransaction = false) { - foreach (TItemType item in this) item.Save(conn); - } + bool ownsConnection = conn == null; + bool ownsTransaction = false; + try + { + if (conn == null) conn = ConnectorBase.NewInstance(); + if (withTransaction && !conn.HasTransaction) + { + ownsTransaction = true; + conn.BeginTransaction(); + } - public virtual void SaveAll() - { - foreach (TItemType item in this) item.Save(); + foreach (TItemType item in this) + item.Save(conn); + + if (ownsTransaction) + { + conn.CommitTransaction(); + ownsTransaction = false; + } + } + catch (Exception ex) + { + throw ex; + } + finally + { + if (conn != null && ownsConnection) + { + conn.Close(); + conn.Dispose(); + conn = null; + } + } } - public virtual void SaveAll(ConnectorBase conn, bool withTransaction) + public virtual async Task SaveAllAsync(ConnectorBase conn = null, bool withTransaction = false, CancellationToken? cancellationToken = null) { bool ownsConnection = conn == null; bool ownsTransaction = false; @@ -34,7 +61,10 @@ public virtual void SaveAll(ConnectorBase conn, bool withTransaction) ownsTransaction = true; conn.BeginTransaction(); } - foreach (TItemType item in this) item.Save(conn); + + foreach (TItemType item in this) + await item.SaveAsync(conn, cancellationToken); + if (ownsTransaction) { conn.CommitTransaction(); @@ -56,15 +86,28 @@ public virtual void SaveAll(ConnectorBase conn, bool withTransaction) } } - public virtual void SaveAll(bool withTransaction) + public void SaveAll(bool withTransaction) { SaveAll(null, withTransaction); } + public Task SaveAllAsync(bool withTransaction, CancellationToken? cancellationToken = null) + { + return SaveAllAsync(null, withTransaction, cancellationToken); + } + + public Task SaveAllAsync(CancellationToken cancellationToken) + { + return SaveAllAsync(null, false, cancellationToken); + } + public static TListType FromReader(DataReader reader) { TListType coll = new TListType(); - while (reader.Read()) coll.Add(AbstractRecord.FromReader(reader)); + + while (reader.Read()) + coll.Add(AbstractRecord.FromReader(reader)); + return coll; } @@ -76,22 +119,27 @@ public static async Task FromReaderAsync(DataReader reader, Cancellat return coll; } - public static TListType FetchAll() + public static TListType FetchAll(ConnectorBase conn = null) { - using (DataReader reader = new Query(AbstractRecord.Schema).ExecuteReader()) + using (var reader = new Query(AbstractRecord.Schema).ExecuteReader(conn)) { return FromReader(reader); } } - public static TListType FetchAll(ConnectorBase conn) + public static async Task FetchAllAsync(ConnectorBase conn = null, CancellationToken? cancellationToken = null) { - using (DataReader reader = new Query(AbstractRecord.Schema).ExecuteReader(conn)) + using (var reader = await new Query(AbstractRecord.Schema).ExecuteReaderAsync(conn, cancellationToken)) { - return FromReader(reader); + return await FromReaderAsync(reader, cancellationToken); } } + public static Task FetchAllAsync(CancellationToken cancellationToken) + { + return FetchAllAsync(null, cancellationToken); + } + public static TListType Where(string columnName, object columnValue) { Query qry = new Query(AbstractRecord.Schema); diff --git a/SequelNet/Sql/RecordEntity/IRecord.cs b/SequelNet/Sql/RecordEntity/IRecord.cs index a074979e..d6352f53 100644 --- a/SequelNet/Sql/RecordEntity/IRecord.cs +++ b/SequelNet/Sql/RecordEntity/IRecord.cs @@ -1,4 +1,6 @@ using SequelNet.Connector; +using System.Threading; +using System.Threading.Tasks; namespace SequelNet { @@ -17,11 +19,13 @@ public interface IRecord bool IsColumnMutated(string column); bool HasMutatedColumns(); - void Insert(ConnectorBase connection = null, string userName = null); - void Update(ConnectorBase connection = null, string userName = null); + void Insert(ConnectorBase connection = null); + Task InsertAsync(ConnectorBase connection = null, CancellationToken? cancellationToken = null); + void Update(ConnectorBase connection = null); + Task UpdateAsync(ConnectorBase connection = null, CancellationToken? cancellationToken = null); void Read(DataReader reader); - void Save(string userName = null); - void Save(ConnectorBase connection, string userName = null); + void Save(ConnectorBase connection = null); + Task SaveAsync(ConnectorBase connection = null, CancellationToken? cancellationToken = null); /// /// Loads a record from the db, by matching the Primary Key to . @@ -31,6 +35,15 @@ public interface IRecord /// An optional db connection to use when executing the query. void LoadByKey(object primaryKeyValue, ConnectorBase connection = null); + /// + /// Loads a record from the db, by matching the Primary Key to . + /// If the record was loaded, it will be marked as an "old" record. + /// + /// The columns' values to match. Could be a String or an IEnumerable of strings. Must match the Primary Key. + /// An optional db connection to use when executing the query. + /// Cancellation token. + Task LoadByKeyAsync(object primaryKeyValue, ConnectorBase connection = null, CancellationToken? cancellationToken = null); + /// /// Loads a record from the db, by matching to . /// If the record was loaded, it will be marked as an "old" record. @@ -39,5 +52,14 @@ public interface IRecord /// The columns' values to match. Could be a String or an IEnumerable of strings. Must match the /// An optional db connection to use when executing the query. void LoadByParam(object columnName, object value, ConnectorBase connection = null); + + /// + /// Loads a record from the db, by matching to . + /// If the record was loaded, it will be marked as an "old" record. + /// + /// The column's name to Where. Could be a String or an IEnumerable of strings. + /// The columns' values to match. Could be a String or an IEnumerable of strings. Must match the + /// An optional db connection to use when executing the query. + Task LoadByParamAsync(object columnName, object value, ConnectorBase connection = null, CancellationToken? cancellationToken = null); } } diff --git a/SequelNet/Sql/RecordEntity/IRecordList.cs b/SequelNet/Sql/RecordEntity/IRecordList.cs index e091da36..acf419f8 100644 --- a/SequelNet/Sql/RecordEntity/IRecordList.cs +++ b/SequelNet/Sql/RecordEntity/IRecordList.cs @@ -1,12 +1,12 @@ using SequelNet.Connector; +using System.Threading; +using System.Threading.Tasks; namespace SequelNet { public interface IRecordList { - void SaveAll(ConnectorBase conn); - void SaveAll(); - void SaveAll(ConnectorBase conn, bool withTransaction); - void SaveAll(bool withTransaction); + void SaveAll(ConnectorBase conn = null, bool withTransaction = false); + Task SaveAllAsync(ConnectorBase conn = null, bool withTransaction = false, CancellationToken? cancellationToken = null); } }