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);
}
}