diff --git a/PetaPoco/Core/ColumnInfo.cs b/PetaPoco/Core/ColumnInfo.cs index 8168691b..afa7d6f0 100644 --- a/PetaPoco/Core/ColumnInfo.cs +++ b/PetaPoco/Core/ColumnInfo.cs @@ -92,6 +92,18 @@ public class ColumnInfo /// public string UpdateTemplate { get; set; } + /// + /// Creates and populates a ColumnInfo from the attributes of a POCO property. + /// + /// The POCO property to use for initializing the ColumnInfo. + /// A ColumnInfo instance. + public static ColumnInfo FromProperty(PropertyInfo propertyInfo) + { + var ci = new ColumnInfo(); + PopulateFromProperty(propertyInfo, ref ci, out _); + return ci; + } + internal static void PopulateFromProperty(PropertyInfo pi, ref ColumnInfo ci, out ColumnAttribute columnAttr) { // Check if declaring poco has [Explicit] attribute @@ -123,17 +135,5 @@ internal static void PopulateFromProperty(PropertyInfo pi, ref ColumnInfo ci, ou } } } - - /// - /// Creates and populates a ColumnInfo from the attributes of a POCO property. - /// - /// The POCO property to use for initializing the ColumnInfo. - /// A ColumnInfo instance. - public static ColumnInfo FromProperty(PropertyInfo propertyInfo) - { - var ci = new ColumnInfo(); - PopulateFromProperty(propertyInfo, ref ci, out _); - return ci; - } } } diff --git a/PetaPoco/Core/IGridReader.cs b/PetaPoco/Core/IGridReader.cs index a2406075..1681dec3 100644 --- a/PetaPoco/Core/IGridReader.cs +++ b/PetaPoco/Core/IGridReader.cs @@ -8,6 +8,8 @@ namespace PetaPoco /// public interface IGridReader : IDisposable { + #region ReadSinglePoco + /// /// Performs a read, returning the results as an collection. /// @@ -15,6 +17,10 @@ public interface IGridReader : IDisposable /// An enumerable collection of POCOs containing the result records. IEnumerable Read(); + #endregion + + #region ReadMultiPoco : auto-mapping + /// IEnumerable Read(); @@ -31,6 +37,10 @@ public interface IGridReader : IDisposable /// An enumerable collection of POCOs containing the result records. IEnumerable Read(); + #endregion + + #region ReadMultiPoco : custom-mapping + /// IEnumerable Read(Func func); @@ -48,5 +58,7 @@ public interface IGridReader : IDisposable /// A callback function to used to connect the POCO instances, or to let PetaPoco automatically deduce the relationships. /// An enumerable collection of POCOs containing the result records. IEnumerable Read(Func func); + + #endregion } } diff --git a/PetaPoco/Core/PocoData.cs b/PetaPoco/Core/PocoData.cs index 255f4ef0..a9e9ac31 100644 --- a/PetaPoco/Core/PocoData.cs +++ b/PetaPoco/Core/PocoData.cs @@ -74,6 +74,14 @@ public PocoData(Type type, IMapper defaultMapper) QueryColumns = (from c in Columns where !c.Value.ResultColumn || c.Value.AutoSelectedResultColumn select c.Key).ToArray(); } + public static PocoData ForType(Type type, IMapper defaultMapper) + { + if (type == typeof(System.Dynamic.ExpandoObject)) + throw new InvalidOperationException("Can't use dynamic types with this method"); + + return _pocoDatas.GetOrAdd(type, () => new PocoData(type, defaultMapper)); + } + public static PocoData ForObject(object obj, string primaryKeyName, IMapper defaultMapper) { var t = obj.GetType(); @@ -97,20 +105,6 @@ public static PocoData ForObject(object obj, string primaryKeyName, IMapper defa return ForType(t, defaultMapper); } - public static PocoData ForType(Type type, IMapper defaultMapper) - { - if (type == typeof(System.Dynamic.ExpandoObject)) - throw new InvalidOperationException("Can't use dynamic types with this method"); - - return _pocoDatas.GetOrAdd(type, () => new PocoData(type, defaultMapper)); - } - - private static bool IsIntegralType(Type type) - { - var tc = Type.GetTypeCode(type); - return tc >= TypeCode.SByte && tc <= TypeCode.UInt64; - } - // Create factory function that can convert a IDataReader record into a POCO public Delegate GetFactory(string sql, string connectionString, int firstColumn, int countColumns, IDataReader reader, IMapper defaultMapper) { @@ -393,6 +387,12 @@ private static Func GetConverter(IMapper mapper, PocoColumn pc, return null; } + private static bool IsIntegralType(Type type) + { + var tc = Type.GetTypeCode(type); + return tc >= TypeCode.SByte && tc <= TypeCode.UInt64; + } + private static T RecurseInheritedTypes(Type t, Func cb) { while (t != null) diff --git a/PetaPoco/Database.cs b/PetaPoco/Database.cs index e801890a..2d87c20e 100644 --- a/PetaPoco/Database.cs +++ b/PetaPoco/Database.cs @@ -18,46 +18,27 @@ namespace PetaPoco { /// - public class Database : IDatabase + public partial class Database : IDatabase { -#region Internal operations - - internal void DoPreExecute(IDbCommand cmd) - { - if (CommandTimeout > 0 || OneTimeCommandTimeout > 0) - { - cmd.CommandTimeout = OneTimeCommandTimeout > 0 ? OneTimeCommandTimeout : CommandTimeout; - OneTimeCommandTimeout = 0; - } - - _provider.PreExecute(cmd); - OnExecutingCommand(cmd); - - _lastSql = cmd.CommandText; - _lastArgs = cmd.Parameters.Cast().Select(parameter => parameter.Value).ToArray(); - } - -#endregion - -#region Member Fields + #region Member Fields private IMapper _defaultMapper; private string _connectionString; private IProvider _provider; + private IsolationLevel? _isolationLevel; private IDbConnection _sharedConnection; private IDbTransaction _transaction; + private DbProviderFactory _factory; private int _sharedConnectionDepth; private int _transactionDepth; private bool _transactionCancelled; + private string _paramPrefix; private string _lastSql; private object[] _lastArgs; - private string _paramPrefix; - private DbProviderFactory _factory; - private IsolationLevel? _isolationLevel; -#endregion + #endregion -#region Constructors + #region Constructors #if !NETSTANDARD /// @@ -121,15 +102,6 @@ public Database(IDbConnection connection, IMapper defaultMapper = null) Initialise(DatabaseProvider.Resolve(_sharedConnection.GetType(), false, _connectionString), defaultMapper); } - private void SetupFromConnection(IDbConnection connection) - { - _sharedConnection = connection; - _connectionString = connection.ConnectionString; - - // Prevent closing external connection - _sharedConnectionDepth = 2; - } - /// /// Constructs an instance using a supplied connection string and provider name. /// @@ -203,7 +175,7 @@ public Database(IDatabaseBuildConfiguration configuration) if (configuration == null) throw new ArgumentNullException(nameof(configuration)); - var settings = (IBuildConfigurationSettings) configuration; + var settings = (IBuildConfigurationSettings)configuration; IMapper defaultMapper = null; settings.TryGetSetting(DatabaseConfigurationExtensions.DefaultMapper, v => defaultMapper = v); @@ -283,6 +255,15 @@ public Database(IDatabaseBuildConfiguration configuration) settings.TryGetSetting>(DatabaseConfigurationExtensions.ExceptionThrown, v => ExceptionThrown += v); } + private void SetupFromConnection(IDbConnection connection) + { + _sharedConnection = connection; + _connectionString = connection.ConnectionString; + + // Prevent closing external connection + _sharedConnectionDepth = 2; + } + /// /// Provides common initialization for the various constructors. /// @@ -301,15 +282,9 @@ private void Initialise(IProvider provider, IMapper mapper) _defaultMapper = mapper ?? new ConventionMapper(); } -#endregion - -#region Connection Management + #endregion - /// - /// When set to the first opened connection is kept alive until or is called. - /// - /// - public bool KeepConnectionAlive { get; set; } + #region Connection Management (IConnection Implementation) /// /// Provides access to the currently open shared connection. @@ -430,14 +405,14 @@ public void Dispose() CloseSharedConnection(); } -#endregion + #endregion -#region Transaction Management + #region Transaction Management (ITransactionAccessor, IDatabase implementation) - /// + /// IDbTransaction ITransactionAccessor.Transaction => _transaction; - /// + /// public ITransaction GetTransaction() => new Transaction(this); @@ -458,7 +433,7 @@ public virtual void OnEndTransaction() TransactionEnding?.Invoke(this, new DbTransactionEventArgs(_transaction)); } - /// + /// public void BeginTransaction() { _transactionDepth++; @@ -473,11 +448,11 @@ public void BeginTransaction() } #if ASYNC - /// + /// public Task BeginTransactionAsync() => BeginTransactionAsync(CancellationToken.None); - /// + /// public async Task BeginTransactionAsync(CancellationToken cancellationToken) { if (_sharedConnection is DbConnection asyncConn) @@ -506,6 +481,36 @@ public async Task BeginTransactionAsync(CancellationToken cancellationToken) } #endif + /// + public void AbortTransaction() + { + _transactionCancelled = true; + CompleteTransaction(); + } + +#if ASYNC + public Task AbortTransactionAsync() + { + this._transactionCancelled = true; + return CompleteTransactionAsync(); + } +#endif + + /// + public void CompleteTransaction() + { + if ((--_transactionDepth) == 0) + CleanupTransaction(); + } + +#if ASYNC + public async Task CompleteTransactionAsync() + { + if ((--_transactionDepth) == 0) + await CleanupTransactionAsync().ConfigureAwait(false); + } +#endif + /// /// Internal helper to cleanup transaction. /// @@ -524,20 +529,6 @@ private void CleanupTransaction() CloseSharedConnection(); } - /// - public void AbortTransaction() - { - _transactionCancelled = true; - CompleteTransaction(); - } - - /// - public void CompleteTransaction() - { - if ((--_transactionDepth) == 0) - CleanupTransaction(); - } - #if ASYNC #pragma warning disable 1998 private async Task CleanupTransactionAsync() @@ -564,633 +555,946 @@ private async Task CleanupTransactionAsync() } } #pragma warning restore 1998 +#endif - public Task AbortTransactionAsync() + #endregion + + #region Exception Reporting and Logging + + /// + /// Called if an exception occurs during processing of a DB operation. Override to provide custom logging/handling. + /// + /// The exception instance. + /// to re-throw the exception, to suppress it. + public virtual bool OnException(Exception ex) { - this._transactionCancelled = true; - return CompleteTransactionAsync(); + System.Diagnostics.Debug.WriteLine(ex.ToString()); + System.Diagnostics.Debug.WriteLine(LastCommand); + + var args = new ExceptionEventArgs(ex); + ExceptionThrown?.Invoke(this, new ExceptionEventArgs(ex)); + return args.Raise; } - public async Task CompleteTransactionAsync() + /// + /// Called when DB connection opened. + /// + /// + /// Override this method to provide custom logging of opened connections, or to provide a proxy IDbConnection. + /// + /// The newly-opened IDbConnection. + /// The same or a replacement IDbConnection. + public virtual IDbConnection OnConnectionOpened(IDbConnection conn) { - if ((--_transactionDepth) == 0) - await CleanupTransactionAsync().ConfigureAwait(false); + var args = new DbConnectionEventArgs(conn); + ConnectionOpened?.Invoke(this, args); + return args.Connection; } -#endif -#endregion + /// + /// Called before a DB connection is opened. + /// + /// + /// Override this method to provide custom logging of opening connections, or to provide a proxy IDbConnection. + /// + /// The soon-to-be-opened IDbConnection. + /// The same or a replacement IDbConnection. + public virtual IDbConnection OnConnectionOpening(IDbConnection conn) + { + var args = new DbConnectionEventArgs(conn); + ConnectionOpening?.Invoke(this, args); + return args.Connection; + } -#region Command Management + /// + /// Called when DB connection closed. + /// + /// The soon-to-be-closed IDBConnection. + public virtual void OnConnectionClosing(IDbConnection conn) + { + ConnectionClosing?.Invoke(this, new DbConnectionEventArgs(conn)); + } /// - /// Adds a parameter to a DB command. + /// Called just before an DB command is executed. /// - /// A reference to the IDbCommand to which the parameter is to be added. - /// The value to assign to the parameter. - /// Optional, a reference to the property info of the POCO property from which the value is coming. - private void AddParam(IDbCommand cmd, object value, PocoColumn pc) + /// + /// Override this method to provide custom logging of commands, modification of the IDbCommand before it's executed, or any other custom actions that should be performed before every command + /// + /// The command to be executed. + public virtual void OnExecutingCommand(IDbCommand cmd) { - // Convert value to from poco type to db type - if (pc?.PropertyInfo != null) - { - var mapper = Mappers.GetMapper(pc.PropertyInfo.DeclaringType, _defaultMapper); - var fn = mapper.GetToDbConverter(pc.PropertyInfo); - if (fn != null) - value = fn(value); - } + CommandExecuting?.Invoke(this, new DbCommandEventArgs(cmd)); + } - // Support passed in parameters - if (value is IDbDataParameter idbParam) - { - if (cmd.CommandType == CommandType.Text) - idbParam.ParameterName = cmd.Parameters.Count.EnsureParamPrefix(_paramPrefix); - else if (idbParam.ParameterName?.StartsWith(_paramPrefix) != true) - idbParam.ParameterName = idbParam.ParameterName.EnsureParamPrefix(_paramPrefix); + /// + /// Called on completion of command execution. + /// + /// + /// Override this method to provide custom logging or other actions after every command has completed. + /// + /// The IDbCommand that finished executing. + public virtual void OnExecutedCommand(IDbCommand cmd) + { + CommandExecuted?.Invoke(this, new DbCommandEventArgs(cmd)); + } - cmd.Parameters.Add(idbParam); - } - else - { - var p = cmd.CreateParameter(); - p.ParameterName = cmd.Parameters.Count.EnsureParamPrefix(_paramPrefix); - SetParameterProperties(p, value, pc); + #endregion - cmd.Parameters.Add(p); - } - } + #region ExecuteNonQuery, ExecuteAsync - private void SetParameterProperties(IDbDataParameter p, object value, PocoColumn pc) - { - // Assign the parameter value - if (value == null) - { - p.Value = DBNull.Value; + /// + public int Execute(Sql sql) + => Execute(sql.SQL, sql.Arguments); - if (pc?.PropertyInfo.PropertyType.Name == "Byte[]") - p.DbType = DbType.Binary; - } - else - { - // Give the database type first crack at converting to DB required type - value = _provider.MapParameterValue(value); + /// + public int Execute(string sql, params object[] args) + => ExecuteInternal(CommandType.Text, sql, args); - var t = value.GetType(); +#if ASYNC + public Task ExecuteAsync(Sql sql) + => ExecuteInternalAsync(CancellationToken.None, CommandType.Text, sql.SQL, sql.Arguments); - if (t == typeof(string) && pc?.ForceToAnsiString == true) - { - t = typeof(AnsiString); - value = value.ToAnsiString(); - } - if (t == typeof(DateTime) && pc?.ForceToDateTime2 == true) - { - t = typeof(DateTime2); - value = ((DateTime)value).ToDateTime2(); - } + public Task ExecuteAsync(string sql, params object[] args) + => ExecuteInternalAsync(CancellationToken.None, CommandType.Text, sql, args); - if (t.IsEnum) // PostgreSQL .NET driver wont cast enum to int + public Task ExecuteAsync(CancellationToken cancellationToken, Sql sql) + => ExecuteInternalAsync(cancellationToken, CommandType.Text, sql.SQL, sql.Arguments); + + public Task ExecuteAsync(CancellationToken cancellationToken, string sql, params object[] args) + => ExecuteInternalAsync(cancellationToken, CommandType.Text, sql, args); +#endif + + protected virtual int ExecuteInternal(CommandType commandType, string sql, params object[] args) + { + try + { + OpenSharedConnection(); + try { - p.Value = Convert.ChangeType(value, ((Enum)value).GetTypeCode()); + using (var cmd = CreateCommand(_sharedConnection, commandType, sql, args)) + { + return ExecuteNonQueryHelper(cmd); + } } - else if (t == typeof(Guid) && !_provider.HasNativeGuidSupport) + finally { - p.Value = value.ToString(); - p.DbType = DbType.String; - p.Size = 40; + CloseSharedConnection(); } - else if (t == typeof(string)) - { - // out of memory exception occurs if trying to save more than 4000 characters to SQL Server CE NText column. Set before attempting to set Size, or Size will always max out at 4000 - if ((value as string).Length + 1 > 4000 && p.GetType().Name == "SqlCeParameter") - p.GetType().GetProperty("SqlDbType").SetValue(p, SqlDbType.NText, null); + } + catch (Exception x) + { + if (OnException(x)) + throw; + return -1; + } + } - p.Size = Math.Max((value as string).Length + 1, 4000); // Help query plan caching by using common size - p.Value = value; - } - else if (t == typeof(AnsiString)) +#if ASYNC + protected virtual async Task ExecuteInternalAsync(CancellationToken cancellationToken, CommandType commandType, string sql, params object[] args) + { + try + { + await OpenSharedConnectionAsync(cancellationToken).ConfigureAwait(false); + try { - var asValue = (value as AnsiString).Value; - if (asValue == null) - { - p.Size = 0; - p.Value = DBNull.Value; - } - else + using (var cmd = CreateCommand(_sharedConnection, commandType, sql, args)) { - p.Size = Math.Max(asValue.Length + 1, 4000); - p.Value = asValue; + return await ExecuteNonQueryHelperAsync(cancellationToken, cmd).ConfigureAwait(false); } - // Thanks @DataChomp for pointing out the SQL Server indexing performance hit of using wrong string type on varchar - p.DbType = DbType.AnsiString; - } - else if (t == typeof(DateTime2)) - { - var dt2Value = (value as DateTime2)?.Value; - p.Value = dt2Value ?? (object)DBNull.Value; - p.DbType = DbType.DateTime2; - } - else if (value.GetType().Name == "SqlGeography") //SqlGeography is a CLR Type - { - p.GetType().GetProperty("UdtTypeName").SetValue(p, "geography", null); //geography is the equivalent SQL Server Type - p.Value = value; - } - else if (value.GetType().Name == "SqlGeometry") //SqlGeometry is a CLR Type - { - p.GetType().GetProperty("UdtTypeName").SetValue(p, "geometry", null); //geography is the equivalent SQL Server Type - p.Value = value; - } - else if (t == typeof(byte[])) - { - p.Value = value; - p.DbType = DbType.Binary; } - else + finally { - p.Value = value; + CloseSharedConnection(); } } + catch (Exception x) + { + if (OnException(x)) + throw; + return -1; + } } +#endif - public IDbCommand CreateCommand(IDbConnection connection, string sql, params object[] args) - => CreateCommand(connection, CommandType.Text, sql, args); + #endregion - public IDbCommand CreateCommand(IDbConnection connection, CommandType commandType, string sql, params object[] args) - { - var cmd = connection.CreateCommand(); + #region ExecuteScalar, ExecuteScalarAsync + + /// + public T ExecuteScalar(Sql sql) + => ExecuteScalar(sql.SQL, sql.Arguments); + + /// + public T ExecuteScalar(string sql, params object[] args) + => ExecuteScalarInternal(CommandType.Text, sql, args); + +#if ASYNC + /// + public Task ExecuteScalarAsync(Sql sql) + => ExecuteScalarInternalAsync(CancellationToken.None, CommandType.Text, sql.SQL, sql.Arguments); + + /// + public Task ExecuteScalarAsync(string sql, params object[] args) + => ExecuteScalarInternalAsync(CancellationToken.None, CommandType.Text, sql, args); + + /// + public Task ExecuteScalarAsync(CancellationToken cancellationToken, Sql sql) + => ExecuteScalarInternalAsync(cancellationToken, CommandType.Text, sql.SQL, sql.Arguments); + + /// + public Task ExecuteScalarAsync(CancellationToken cancellationToken, string sql, params object[] args) + => ExecuteScalarInternalAsync(cancellationToken, CommandType.Text, sql, args); +#endif + protected virtual T ExecuteScalarInternal(CommandType commandType, string sql, params object[] args) + { try { - cmd.CommandType = commandType; - cmd.Transaction = _transaction; - - switch (commandType) + OpenSharedConnection(); + try { - case CommandType.Text: - // Perform named argument replacements - if (EnableNamedParams) - { - var newArgs = new List(); - sql = ParametersHelper.ProcessQueryParams(sql, args, newArgs); - args = newArgs.ToArray(); - } + using (var cmd = CreateCommand(_sharedConnection, commandType, sql, args)) + { + var val = ExecuteScalarHelper(cmd); - // Perform parameter prefix replacements - if (_paramPrefix != "@") - sql = sql.ReplaceParamPrefix(_paramPrefix); - sql = sql.Replace("@@", "@"); // <- double @@ escapes a single @ - break; - case CommandType.StoredProcedure: - args = ParametersHelper.ProcessStoredProcParams(cmd, args, SetParameterProperties); - break; - case CommandType.TableDirect: - break; + // Handle nullable types + var u = Nullable.GetUnderlyingType(typeof(T)); + if (u != null && (val == null || val == DBNull.Value)) + return default(T); + + return (T) Convert.ChangeType(val, u == null ? typeof(T) : u); + } + } + finally + { + CloseSharedConnection(); } + } + catch (Exception x) + { + if (OnException(x)) + throw; + return default(T); + } + } - cmd.CommandText = sql; +#if ASYNC + protected virtual async Task ExecuteScalarInternalAsync(CancellationToken cancellationToken, CommandType commandType, string sql, params object[] args) + { + try + { + await OpenSharedConnectionAsync(cancellationToken).ConfigureAwait(false); + try + { + using (var cmd = CreateCommand(_sharedConnection, commandType, sql, args)) + { + var val = await ExecuteScalarHelperAsync(cancellationToken, cmd).ConfigureAwait(false); - foreach (var item in args) - AddParam(cmd, item, null); + var u = Nullable.GetUnderlyingType(typeof(T)); + if (u != null && (val == null || val == DBNull.Value)) + return default(T); - return cmd; + return (T) Convert.ChangeType(val, u == null ? typeof(T) : u); + } + } + finally + { + CloseSharedConnection(); + } } - catch + catch (Exception x) { - cmd.Dispose(); - throw; + if (OnException(x)) + throw; + return default(T); } } +#endif - /// - /// Creates an IDbDataParameter with default values. - /// - /// The IDbDataParameter. - public IDbDataParameter CreateParameter() => _factory.CreateParameter(); + #endregion - /// - /// Creates an IDbDataParameter with the given name and value. - /// - /// The parameter name. - /// The parameter value. - /// The IDbDataParameter. - public IDbDataParameter CreateParameter(string name, object value) - => CreateParameter(name, value, ParameterDirection.Input); + #region Query, QueryAsync : Single-Poco - /// - /// Creates an IDbDataParameter with the given name and direction. - /// - /// The parameter name. - /// The parameter direction. - /// The IDbDataParameter. - public IDbDataParameter CreateParameter(string name, ParameterDirection direction) - => CreateParameter(name, null, direction); + /// + public IEnumerable Query() + => Query(string.Empty); - /// - /// Create an IDbParameter with the given ParameterName, Value, and Direction. - /// - /// The parameter name. - /// The parameter value. - /// The parameter direction. - /// The IDbDataParameter. - public IDbDataParameter CreateParameter(string name, object value, ParameterDirection direction) + /// + public IEnumerable Query(Sql sql) + => Query(sql.SQL, sql.Arguments); + + /// + public IEnumerable Query(string sql, params object[] args) { - var result = CreateParameter(); - result.ParameterName = name; - result.Value = value; - result.Direction = direction; - return result; + if (EnableAutoSelect) + sql = AutoSelectHelper.AddSelectClause(_provider, sql, _defaultMapper); + + return ExecuteReader(CommandType.Text, sql, args); } -#endregion +#if ASYNC + /// + public Task> QueryAsync() + => QueryAsync(CancellationToken.None, CommandType.Text, string.Empty); -#region Exception Reporting and Logging + /// + public Task> QueryAsync(Sql sql) + => QueryAsync(CancellationToken.None, CommandType.Text, sql.SQL, sql.Arguments); - /// - /// Called if an exception occurs during processing of a DB operation. Override to provide custom logging/handling. - /// - /// The exception instance. - /// to re-throw the exception, to suppress it. - public virtual bool OnException(Exception ex) - { - System.Diagnostics.Debug.WriteLine(ex.ToString()); - System.Diagnostics.Debug.WriteLine(LastCommand); + /// + public Task> QueryAsync(string sql, params object[] args) + => QueryAsync(CancellationToken.None, CommandType.Text, sql, args); - var args = new ExceptionEventArgs(ex); - ExceptionThrown?.Invoke(this, new ExceptionEventArgs(ex)); - return args.Raise; - } + /// + public Task> QueryAsync(CancellationToken cancellationToken) + => QueryAsync(cancellationToken, CommandType.Text, string.Empty); - /// - /// Called when DB connection opened. - /// - /// - /// Override this method to provide custom logging of opened connections, or to provide a proxy IDbConnection. - /// - /// The newly-opened IDbConnection. - /// The same or a replacement IDbConnection. - public virtual IDbConnection OnConnectionOpened(IDbConnection conn) - { - var args = new DbConnectionEventArgs(conn); - ConnectionOpened?.Invoke(this, args); - return args.Connection; - } + /// + public Task> QueryAsync(CancellationToken cancellationToken, Sql sql) + => QueryAsync(cancellationToken, CommandType.Text, sql.SQL, sql.Arguments); - /// - /// Called before a DB connection is opened. - /// - /// - /// Override this method to provide custom logging of opening connections, or to provide a proxy IDbConnection. - /// - /// The soon-to-be-opened IDbConnection. - /// The same or a replacement IDbConnection. - public virtual IDbConnection OnConnectionOpening(IDbConnection conn) - { - var args = new DbConnectionEventArgs(conn); - ConnectionOpening?.Invoke(this, args); - return args.Connection; - } + /// + public Task> QueryAsync(CancellationToken cancellationToken, string sql, params object[] args) + => QueryAsync(CancellationToken.None, CommandType.Text, sql, args); - /// - /// Called when DB connection closed. - /// - /// The soon-to-be-closed IDBConnection. - public virtual void OnConnectionClosing(IDbConnection conn) - { - ConnectionClosing?.Invoke(this, new DbConnectionEventArgs(conn)); - } + /// + public Task> QueryAsync(CommandType commandType) + => QueryAsync(CancellationToken.None, commandType, string.Empty); - /// - /// Called just before an DB command is executed. - /// - /// - /// Override this method to provide custom logging of commands, modification of the IDbCommand before it's executed, or any other custom actions that should be performed before every command - /// - /// The command to be executed. - public virtual void OnExecutingCommand(IDbCommand cmd) - { - CommandExecuting?.Invoke(this, new DbCommandEventArgs(cmd)); - } + /// + public Task> QueryAsync(CommandType commandType, Sql sql) + => QueryAsync(CancellationToken.None, commandType, sql.SQL, sql.Arguments); - /// - /// Called on completion of command execution. - /// - /// - /// Override this method to provide custom logging or other actions after every command has completed. - /// - /// The IDbCommand that finished executing. - public virtual void OnExecutedCommand(IDbCommand cmd) + /// + public Task> QueryAsync(CommandType commandType, string sql, params object[] args) + => QueryAsync(CancellationToken.None, commandType, sql, args); + + /// + public Task> QueryAsync(CancellationToken cancellationToken, CommandType commandType) + => QueryAsync(cancellationToken, commandType, string.Empty); + + /// + public Task> QueryAsync(CancellationToken cancellationToken, CommandType commandType, Sql sql) + => QueryAsync(cancellationToken, commandType, sql.SQL, sql.Arguments); + + /// + public Task> QueryAsync(CancellationToken cancellationToken, CommandType commandType, string sql, params object[] args) { - CommandExecuted?.Invoke(this, new DbCommandEventArgs(cmd)); + if (EnableAutoSelect) + sql = AutoSelectHelper.AddSelectClause(_provider, sql, _defaultMapper); + + return ExecuteReaderAsync(cancellationToken, commandType, sql, args); } -#endregion + /// + public Task QueryAsync(Action receivePocoCallback) + => QueryAsync(receivePocoCallback, CancellationToken.None, CommandType.Text, string.Empty); -#region operation: Execute + /// + public Task QueryAsync(Action receivePocoCallback, Sql sql) + => QueryAsync(receivePocoCallback, CancellationToken.None, CommandType.Text, sql.SQL, sql.Arguments); - /// - public int Execute(string sql, params object[] args) - => ExecuteInternal(CommandType.Text, sql, args); + /// + public Task QueryAsync(Action receivePocoCallback, string sql, params object[] args) + => QueryAsync(receivePocoCallback, CancellationToken.None, CommandType.Text, sql, args); - /// - public int Execute(Sql sql) - => Execute(sql.SQL, sql.Arguments); + /// + public Task QueryAsync(Action receivePocoCallback, CancellationToken cancellationToken) + => QueryAsync(receivePocoCallback, cancellationToken, CommandType.Text, string.Empty); - protected virtual int ExecuteInternal(CommandType commandType, string sql, params object[] args) + /// + public Task QueryAsync(Action receivePocoCallback, CancellationToken cancellationToken, Sql sql) + => QueryAsync(receivePocoCallback, cancellationToken, CommandType.Text, sql.SQL, sql.Arguments); + + /// + public Task QueryAsync(Action receivePocoCallback, CancellationToken cancellationToken, string sql, params object[] args) + => QueryAsync(receivePocoCallback, CancellationToken.None, CommandType.Text, sql, args); + + /// + public Task QueryAsync(Action receivePocoCallback, CommandType commandType) + => QueryAsync(receivePocoCallback, CancellationToken.None, commandType, string.Empty); + + /// + public Task QueryAsync(Action receivePocoCallback, CommandType commandType, Sql sql) + => QueryAsync(receivePocoCallback, CancellationToken.None, commandType, sql.SQL, sql.Arguments); + + /// + public Task QueryAsync(Action receivePocoCallback, CommandType commandType, string sql, params object[] args) + => QueryAsync(receivePocoCallback, CancellationToken.None, commandType, sql, args); + + /// + public Task QueryAsync(Action receivePocoCallback, CancellationToken cancellationToken, CommandType commandType) + => QueryAsync(receivePocoCallback, cancellationToken, commandType, string.Empty); + + /// + public Task QueryAsync(Action receivePocoCallback, CancellationToken cancellationToken, CommandType commandType, Sql sql) + => QueryAsync(receivePocoCallback, cancellationToken, commandType, sql.SQL, sql.Arguments); + + /// + public Task QueryAsync(Action receivePocoCallback, CancellationToken cancellationToken, CommandType commandType, string sql, params object[] args) + { + if (EnableAutoSelect) + sql = AutoSelectHelper.AddSelectClause(_provider, sql, _defaultMapper); + return ExecuteReaderAsync(receivePocoCallback, cancellationToken, commandType, sql, args); + } + +#endif + + protected virtual IEnumerable ExecuteReader(CommandType commandType, string sql, params object[] args) { + OpenSharedConnection(); try { - OpenSharedConnection(); - try + using (var cmd = CreateCommand(_sharedConnection, commandType, sql, args)) { - using (var cmd = CreateCommand(_sharedConnection, commandType, sql, args)) + IDataReader r; + var pd = PocoData.ForType(typeof(T), _defaultMapper); + try { - return ExecuteNonQueryHelper(cmd); + r = ExecuteReaderHelper(cmd); + } + catch (Exception x) + { + if (OnException(x)) + throw; + yield break; + } + + var factory = pd.GetFactory(cmd.CommandText, _sharedConnection.ConnectionString, 0, r.FieldCount, r, + _defaultMapper) as Func; + using (r) + { + while (true) + { + T poco; + try + { + if (!r.Read()) + yield break; + poco = factory(r); + } + catch (Exception x) + { + if (OnException(x)) + throw; + yield break; + } + + yield return poco; + } } - } - finally - { - CloseSharedConnection(); } } - catch (Exception x) + finally { - if (OnException(x)) - throw; - return -1; + CloseSharedConnection(); } } #if ASYNC - - public Task ExecuteAsync(string sql, params object[] args) - => ExecuteInternalAsync(CancellationToken.None, CommandType.Text, sql, args); - - public Task ExecuteAsync(CancellationToken cancellationToken, string sql, params object[] args) - => ExecuteInternalAsync(cancellationToken, CommandType.Text, sql, args); - - public Task ExecuteAsync(Sql sql) - => ExecuteInternalAsync(CancellationToken.None, CommandType.Text, sql.SQL, sql.Arguments); - - public Task ExecuteAsync(CancellationToken cancellationToken, Sql sql) - => ExecuteInternalAsync(cancellationToken, CommandType.Text, sql.SQL, sql.Arguments); - - protected virtual async Task ExecuteInternalAsync(CancellationToken cancellationToken, CommandType commandType, string sql, params object[] args) + protected virtual async Task> ExecuteReaderAsync(CancellationToken cancellationToken, CommandType commandType, string sql, object[] args) { + await OpenSharedConnectionAsync(cancellationToken).ConfigureAwait(false); + var cmd = CreateCommand(_sharedConnection, commandType, sql, args); + IDataReader reader = null; + var pd = PocoData.ForType(typeof(T), _defaultMapper); + try { - await OpenSharedConnectionAsync(cancellationToken).ConfigureAwait(false); + reader = await ExecuteReaderHelperAsync(cancellationToken, cmd).ConfigureAwait(false); + } + catch (Exception e) + { + if (OnException(e)) + throw; try { - using (var cmd = CreateCommand(_sharedConnection, commandType, sql, args)) - { - return await ExecuteNonQueryHelperAsync(cancellationToken, cmd).ConfigureAwait(false); - } + cmd?.Dispose(); + reader?.Dispose(); } - finally + catch { - CloseSharedConnection(); + // ignored } - } - catch (Exception x) - { - if (OnException(x)) - throw; - return -1; - } - } - -#endif -#endregion - -#region operation: ExecuteScalar + return AsyncReader.Empty(); + } - /// - public T ExecuteScalar(string sql, params object[] args) - => ExecuteScalarInternal(CommandType.Text, sql, args); + var factory = + pd.GetFactory(cmd.CommandText, _sharedConnection.ConnectionString, 0, reader.FieldCount, reader, _defaultMapper) as Func; - /// - public T ExecuteScalar(Sql sql) - => ExecuteScalar(sql.SQL, sql.Arguments); + return new AsyncReader(this, cmd, reader, factory); + } - protected virtual T ExecuteScalarInternal(CommandType commandType, string sql, params object[] args) + protected virtual async Task ExecuteReaderAsync(Action processPoco, CancellationToken cancellationToken, CommandType commandType, string sql, object[] args) { + await OpenSharedConnectionAsync(cancellationToken).ConfigureAwait(false); try { - OpenSharedConnection(); - try + using (var cmd = CreateCommand(_sharedConnection, commandType, sql, args)) { - using (var cmd = CreateCommand(_sharedConnection, commandType, sql, args)) - { - var val = ExecuteScalarHelper(cmd); - - // Handle nullable types - var u = Nullable.GetUnderlyingType(typeof(T)); - if (u != null && (val == null || val == DBNull.Value)) - return default(T); + IDataReader reader; + var pd = PocoData.ForType(typeof(T), _defaultMapper); - return (T) Convert.ChangeType(val, u == null ? typeof(T) : u); + try + { + reader = await ExecuteReaderHelperAsync(cancellationToken, cmd).ConfigureAwait(false); + } + catch (Exception e) + { + if (OnException(e)) + throw; + return; + } + + var readerAsync = reader as DbDataReader; + var factory = + pd.GetFactory(cmd.CommandText, _sharedConnection.ConnectionString, 0, reader.FieldCount, reader, + _defaultMapper) as Func; + + using (reader) + { + while (true) + { + T poco; + try + { + if (readerAsync != null) + { + if (!await readerAsync.ReadAsync(cancellationToken).ConfigureAwait(false)) + return; + } + else + { + if (!reader.Read()) + return; + } + + poco = factory(reader); + processPoco(poco); + } + catch (Exception e) + { + if (OnException(e)) + throw; + return; + } + } } - } - finally - { - CloseSharedConnection(); } } - catch (Exception x) + finally { - if (OnException(x)) - throw; - return default(T); + CloseSharedConnection(); } } +#endif -#if ASYNC + #endregion - /// - public Task ExecuteScalarAsync(string sql, params object[] args) - => ExecuteScalarInternalAsync(CancellationToken.None, CommandType.Text, sql, args); + #region Query : Multi-Poco - /// - public Task ExecuteScalarAsync(CancellationToken cancellationToken, string sql, params object[] args) - => ExecuteScalarInternalAsync(cancellationToken, CommandType.Text, sql, args); + /// + public IEnumerable Query(Sql sql) + => Query(new[] { typeof(T1), typeof(T2) }, null, sql.SQL, sql.Arguments); - /// - public Task ExecuteScalarAsync(Sql sql) - => ExecuteScalarInternalAsync(CancellationToken.None, CommandType.Text, sql.SQL, sql.Arguments); + /// + public IEnumerable Query(Sql sql) + => Query(new[] { typeof(T1), typeof(T2), typeof(T3) }, null, sql.SQL, sql.Arguments); - /// - public Task ExecuteScalarAsync(CancellationToken cancellationToken, Sql sql) - => ExecuteScalarInternalAsync(cancellationToken, CommandType.Text, sql.SQL, sql.Arguments); + public IEnumerable Query(Sql sql) + => Query(new[] { typeof(T1), typeof(T2), typeof(T3), typeof(T4) }, null, sql.SQL, sql.Arguments); + + /// + public IEnumerable Query(Sql sql) + => Query(new[] { typeof(T1), typeof(T2), typeof(T3), typeof(T4), typeof(T5) }, null, sql.SQL, sql.Arguments); + + /// + public IEnumerable Query(string sql, params object[] args) + => Query(new[] { typeof(T1), typeof(T2) }, null, sql, args); + + /// + public IEnumerable Query(string sql, params object[] args) + => Query(new[] { typeof(T1), typeof(T2), typeof(T3) }, null, sql, args); + + /// + public IEnumerable Query(string sql, params object[] args) + => Query(new[] { typeof(T1), typeof(T2), typeof(T3), typeof(T4) }, null, sql, args); + + /// + public IEnumerable Query(string sql, params object[] args) + => Query(new[] { typeof(T1), typeof(T2), typeof(T3), typeof(T4), typeof(T5) }, null, sql, args); + + /// + public IEnumerable Query(Func cb, Sql sql) + => Query(new[] { typeof(T1), typeof(T2) }, cb, sql.SQL, sql.Arguments); + + /// + public IEnumerable Query(Func cb, Sql sql) + => Query(new[] { typeof(T1), typeof(T2), typeof(T3) }, cb, sql.SQL, sql.Arguments); + + /// + public IEnumerable Query(Func cb, Sql sql) + => Query(new[] { typeof(T1), typeof(T2), typeof(T3), typeof(T4) }, cb, sql.SQL, sql.Arguments); + + /// + public IEnumerable Query(Func cb, Sql sql) + => Query(new[] { typeof(T1), typeof(T2), typeof(T3), typeof(T4), typeof(T5) }, cb, sql.SQL, sql.Arguments); + + /// + public IEnumerable Query(Func cb, string sql, params object[] args) + => Query(new[] { typeof(T1), typeof(T2) }, cb, sql, args); + + /// + public IEnumerable Query(Func cb, string sql, params object[] args) + => Query(new[] { typeof(T1), typeof(T2), typeof(T3) }, cb, sql, args); + + /// + public IEnumerable Query(Func cb, string sql, params object[] args) + => Query(new[] { typeof(T1), typeof(T2), typeof(T3), typeof(T4) }, cb, sql, args); + + public IEnumerable Query(Func cb, string sql, params object[] args) + => Query(new[] { typeof(T1), typeof(T2), typeof(T3), typeof(T4), typeof(T5) }, cb, sql, args); - protected virtual async Task ExecuteScalarInternalAsync(CancellationToken cancellationToken, CommandType commandType, string sql, - params object[] args) + /// + public IEnumerable Query(Type[] types, object cb, string sql, params object[] args) { + OpenSharedConnection(); try { - await OpenSharedConnectionAsync(cancellationToken).ConfigureAwait(false); - try + using (var cmd = CreateCommand(_sharedConnection, sql, args)) { - using (var cmd = CreateCommand(_sharedConnection, commandType, sql, args)) + IDataReader r; + try { - var val = await ExecuteScalarHelperAsync(cancellationToken, cmd).ConfigureAwait(false); + r = ExecuteReaderHelper(cmd); + } + catch (Exception x) + { + if (OnException(x)) + throw; + yield break; + } - var u = Nullable.GetUnderlyingType(typeof(T)); - if (u != null && (val == null || val == DBNull.Value)) - return default(T); + var factory = MultiPocoFactory.GetFactory(types, _sharedConnection.ConnectionString, sql, r, _defaultMapper); + if (cb == null) + cb = MultiPocoFactory.GetAutoMapper(types.ToArray()); + var bNeedTerminator = false; + using (r) + { + while (true) + { + TRet poco; + try + { + if (!r.Read()) + break; + poco = factory(r, cb); + } + catch (Exception x) + { + if (OnException(x)) + throw; + yield break; + } - return (T) Convert.ChangeType(val, u == null ? typeof(T) : u); + if (poco != null) + yield return poco; + else + bNeedTerminator = true; + } + + if (bNeedTerminator) + { + var poco = (TRet) (cb as Delegate).DynamicInvoke(new object[types.Length]); + if (poco != null) + yield return poco; + else + yield break; + } } } - finally - { - CloseSharedConnection(); - } + } + finally + { + CloseSharedConnection(); + } + } + + #endregion + + #region QueryMultiple : Multi-POCO Result Set IGridReader + + public IGridReader QueryMultiple(Sql sql) + => QueryMultiple(sql.SQL, sql.Arguments); + + public IGridReader QueryMultiple(string sql, params object[] args) + { + OpenSharedConnection(); + + GridReader result = null; + + var cmd = CreateCommand(_sharedConnection, sql, args); + + try + { + var reader = ExecuteReaderHelper(cmd); + result = new GridReader(this, cmd, reader, _defaultMapper); } catch (Exception x) { if (OnException(x)) throw; - return default(T); } - } -#endif + return result; + } -#endregion + #endregion -#region operation: Fetch + #region Fetch, FetchAsync : Single-Poco - /// + /// public List Fetch() => Fetch(string.Empty); - /// - public List Fetch(string sql, params object[] args) - => Query(sql, args).ToList(); - - /// + /// public List Fetch(Sql sql) => Fetch(sql.SQL, sql.Arguments); - /// - public List Fetch(long page, long itemsPerPage) - => Fetch(page, itemsPerPage, string.Empty); - - /// - public List Fetch(long page, long itemsPerPage, string sql, params object[] args) - => SkipTake((page - 1) * itemsPerPage, itemsPerPage, sql, args); - - /// - public List Fetch(long page, long itemsPerPage, Sql sql) - => SkipTake((page - 1) * itemsPerPage, itemsPerPage, sql.SQL, sql.Arguments); + /// + public List Fetch(string sql, params object[] args) + => Query(sql, args).ToList(); #if ASYNC - /// + /// public Task> FetchAsync() => FetchAsync(CancellationToken.None, CommandType.Text, string.Empty); - /// - public Task> FetchAsync(CommandType commandType) - => FetchAsync(CancellationToken.None, CommandType.Text, string.Empty); + /// + public Task> FetchAsync(Sql sql) + => FetchAsync(CancellationToken.None, CommandType.Text, sql.SQL, sql.Arguments); + + /// + public Task> FetchAsync(string sql, params object[] args) + => FetchAsync(CancellationToken.None, CommandType.Text, sql, args); - /// + /// public Task> FetchAsync(CancellationToken cancellationToken) => FetchAsync(cancellationToken, CommandType.Text, string.Empty); - /// - public Task> FetchAsync(CancellationToken cancellationToken, CommandType commandType) - => FetchAsync(cancellationToken, commandType, string.Empty); + /// + public Task> FetchAsync(CancellationToken cancellationToken, Sql sql) + => FetchAsync(cancellationToken, CommandType.Text, sql.SQL, sql.Arguments); - /// - public Task> FetchAsync(string sql, params object[] args) + /// + public Task> FetchAsync(CancellationToken cancellationToken, string sql, params object[] args) => FetchAsync(CancellationToken.None, CommandType.Text, sql, args); - /// - public Task> FetchAsync(CommandType commandType, string sql, params object[] args) + /// + public Task> FetchAsync(CommandType commandType) + => FetchAsync(CancellationToken.None, CommandType.Text, string.Empty); + + /// + public Task> FetchAsync(CommandType commandType, Sql sql) + => FetchAsync(CancellationToken.None, commandType, sql.SQL, sql.Arguments); + + /// + public Task> FetchAsync(CommandType commandType, string sql, params object[] args) => FetchAsync(CancellationToken.None, commandType, sql, args); - /// - public Task> FetchAsync(CancellationToken cancellationToken, string sql, params object[] args) - => FetchAsync(CancellationToken.None, CommandType.Text, sql, args); + /// + public Task> FetchAsync(CancellationToken cancellationToken, CommandType commandType) + => FetchAsync(cancellationToken, commandType, string.Empty); + + /// + public Task> FetchAsync(CancellationToken cancellationToken, CommandType commandType, Sql sql) + => FetchAsync(cancellationToken, commandType, sql.SQL, sql.Arguments); - /// + /// public async Task> FetchAsync(CancellationToken cancellationToken, CommandType commandType, string sql, params object[] args) { var pocos = new List(); await QueryAsync(p => pocos.Add(p), cancellationToken, commandType, sql, args).ConfigureAwait(false); return pocos; } +#endif - /// - public Task> FetchAsync(Sql sql) - => FetchAsync(CancellationToken.None, CommandType.Text, sql.SQL, sql.Arguments); + #endregion - /// - public Task> FetchAsync(CommandType commandType, Sql sql) - => FetchAsync(CancellationToken.None, commandType, sql.SQL, sql.Arguments); + #region Fetch : Multi-Poco - /// - public Task> FetchAsync(CancellationToken cancellationToken, Sql sql) - => FetchAsync(cancellationToken, CommandType.Text, sql.SQL, sql.Arguments); + /// + public List Fetch(Sql sql) + => Query(sql.SQL, sql.Arguments).ToList(); - /// - public Task> FetchAsync(CancellationToken cancellationToken, CommandType commandType, Sql sql) - => FetchAsync(cancellationToken, commandType, sql.SQL, sql.Arguments); + /// + public List Fetch(Sql sql) + => Query(sql.SQL, sql.Arguments).ToList(); + + /// + public List Fetch(Sql sql) + => Query(sql.SQL, sql.Arguments).ToList(); + + /// + public List Fetch(Sql sql) + => Query(sql.SQL, sql.Arguments).ToList(); + + /// + public List Fetch(string sql, params object[] args) + => Query(sql, args).ToList(); + + /// + public List Fetch(string sql, params object[] args) + => Query(sql, args).ToList(); + + /// + public List Fetch(string sql, params object[] args) + => Query(sql, args).ToList(); + + /// + public List Fetch(string sql, params object[] args) + => Query(sql, args).ToList(); + + /// + public List Fetch(Func cb, Sql sql) + => Query(cb, sql.SQL, sql.Arguments).ToList(); + + /// + public List Fetch(Func cb, Sql sql) + => Query(cb, sql.SQL, sql.Arguments).ToList(); + + /// + public List Fetch(Func cb, Sql sql) + => Query(cb, sql.SQL, sql.Arguments).ToList(); + + public List Fetch(Func cb, Sql sql) + => Query(cb, sql.SQL, sql.Arguments).ToList(); + + /// + public List Fetch(Func cb, string sql, params object[] args) + => Query(cb, sql, args).ToList(); + + /// + public List Fetch(Func cb, string sql, params object[] args) + => Query(cb, sql, args).ToList(); + + /// + public List Fetch(Func cb, string sql, params object[] args) + => Query(cb, sql, args).ToList(); + + /// + public List Fetch(Func cb, string sql, params object[] args) + => Query(cb, sql, args).ToList(); + + #endregion + + #region Fetch, FetchAsync : Paged SkipTake + + /// + public List Fetch(long page, long itemsPerPage) + => Fetch(page, itemsPerPage, string.Empty); - /// + /// + public List Fetch(long page, long itemsPerPage, Sql sql) + => SkipTake((page - 1) * itemsPerPage, itemsPerPage, sql.SQL, sql.Arguments); + + /// + public List Fetch(long page, long itemsPerPage, string sql, params object[] args) + => SkipTake((page - 1) * itemsPerPage, itemsPerPage, sql, args); + +#if ASYNC + /// public Task> FetchAsync(long page, long itemsPerPage) => FetchAsync(page, itemsPerPage, string.Empty); - /// - public Task> FetchAsync(CancellationToken cancellationToken, long page, long itemsPerPage) - => FetchAsync(cancellationToken, page, itemsPerPage, string.Empty); + /// + public Task> FetchAsync(long page, long itemsPerPage, Sql sql) + => FetchAsync(CancellationToken.None, page, itemsPerPage, sql); - /// + /// public Task> FetchAsync(long page, long itemsPerPage, string sql, params object[] args) => FetchAsync(CancellationToken.None, page, itemsPerPage, sql, args); - /// - public Task> FetchAsync(CancellationToken cancellationToken, long page, long itemsPerPage, string sql, params object[] args) - => SkipTakeAsync(cancellationToken, (page - 1) * itemsPerPage, itemsPerPage, sql, args); - - /// - public Task> FetchAsync(long page, long itemsPerPage, Sql sql) - => FetchAsync(CancellationToken.None, page, itemsPerPage, sql); + /// + public Task> FetchAsync(CancellationToken cancellationToken, long page, long itemsPerPage) + => FetchAsync(cancellationToken, page, itemsPerPage, string.Empty); - /// + /// public Task> FetchAsync(CancellationToken cancellationToken, long page, long itemsPerPage, Sql sql) => SkipTakeAsync(cancellationToken, (page - 1) * itemsPerPage, itemsPerPage, sql.SQL, sql.Arguments); + /// + public Task> FetchAsync(CancellationToken cancellationToken, long page, long itemsPerPage, string sql, params object[] args) + => SkipTakeAsync(cancellationToken, (page - 1) * itemsPerPage, itemsPerPage, sql, args); #endif -#endregion + #endregion -#region operation: Page + #region Page, PageAsync - /// - /// Starting with a regular SELECT statement, derives the SQL statements required to query a DB for a page of records and the total number of records. - /// - /// The Type representing a row in the result set. - /// The number of rows to skip before the start of the page. - /// The number of rows in the page. - /// The original SQL select statement. - /// Arguments to any embedded parameters in the SQL. - /// Outputs the SQL statement to query for the total number of matching rows. - /// Outputs the SQL statement to retrieve a single page of matching rows. - /// Thrown when unable to parse the given statement. - protected virtual void BuildPageQueries(long skip, long take, string sql, ref object[] args, out string sqlCount, out string sqlPage) + /// + public Page Page(long page, long itemsPerPage) + => Page(page, itemsPerPage, string.Empty); + + /// + public Page Page(long page, long itemsPerPage, Sql sql) + => Page(page, itemsPerPage, sql.SQL, sql.Arguments); + + /// + public Page Page(long page, long itemsPerPage, string sql, params object[] args) { - if (EnableAutoSelect) - sql = AutoSelectHelper.AddSelectClause(_provider, sql, _defaultMapper); + BuildPageQueries((page - 1) * itemsPerPage, itemsPerPage, sql, ref args, out var sqlCount, out var sqlPage); + return Page(page, itemsPerPage, sqlCount, args, sqlPage, args); + } - SQLParts parts; - if (!Provider.PagingUtility.SplitSQL(sql, out parts)) - throw new Exception("Unable to parse SQL statement for paged query"); + /// + public Page Page(long page, long itemsPerPage, Sql sqlCount, Sql sqlPage) + => Page(page, itemsPerPage, sqlCount.SQL, sqlCount.Arguments, sqlPage.SQL, sqlPage.Arguments); - sqlPage = _provider.BuildPageQuery(skip, take, parts, ref args); - sqlCount = parts.SqlCount; +#if ASYNC + /// + public Task> PageAsync(long page, long itemsPerPage) + => PageAsync(CancellationToken.None, page, itemsPerPage, string.Empty); + + /// + public Task> PageAsync(long page, long itemsPerPage, Sql sql) + => PageAsync(CancellationToken.None, page, itemsPerPage, sql.SQL, sql.Arguments); + + /// + public Task> PageAsync(long page, long itemsPerPage, string sql, params object[] args) + => PageAsync(CancellationToken.None, page, itemsPerPage, sql, args); + + /// + public Task> PageAsync(long page, long itemsPerPage, Sql sqlCount, Sql sqlPage) + => PageAsync(CancellationToken.None, page, itemsPerPage, sqlCount.SQL, sqlCount.Arguments, sqlPage.SQL, sqlPage.Arguments); + + /// + public Task> PageAsync(long page, long itemsPerPage, string sqlCount, object[] countArgs, string sqlPage, object[] pageArgs) + => PageAsync(CancellationToken.None, page, itemsPerPage, sqlCount, countArgs, sqlPage, pageArgs); + + /// + public Task> PageAsync(CancellationToken cancellationToken, long page, long itemsPerPage) + => PageAsync(cancellationToken, page, itemsPerPage, string.Empty); + + /// + public Task> PageAsync(CancellationToken cancellationToken, long page, long itemsPerPage, Sql sql) + => PageAsync(cancellationToken, page, itemsPerPage, sql.SQL, sql.Arguments); + + /// + public Task> PageAsync(CancellationToken cancellationToken, long page, long itemsPerPage, string sql, params object[] args) + { + BuildPageQueries((page - 1) * itemsPerPage, itemsPerPage, sql, ref args, out var sqlCount, out var sqlPage); + return PageAsync(cancellationToken, page, itemsPerPage, sqlCount, args, sqlPage, args); } - /// + /// + public Task> PageAsync(CancellationToken cancellationToken, long page, long itemsPerPage, Sql sqlCount, Sql sqlPage) + => PageAsync(cancellationToken, page, itemsPerPage, sqlCount.SQL, sqlCount.Arguments, sqlPage.SQL, sqlPage.Arguments); +#endif + + /// public Page Page(long page, long itemsPerPage, string sqlCount, object[] countArgs, string sqlPage, object[] pageArgs) { // Save the one-time command time out and use it for both queries @@ -1215,30 +1519,9 @@ public Page Page(long page, long itemsPerPage, string sqlCount, object[] c return result; } - /// - public Page Page(long page, long itemsPerPage) - => Page(page, itemsPerPage, string.Empty); - - /// - public Page Page(long page, long itemsPerPage, string sql, params object[] args) - { - BuildPageQueries((page - 1) * itemsPerPage, itemsPerPage, sql, ref args, out var sqlCount, out var sqlPage); - return Page(page, itemsPerPage, sqlCount, args, sqlPage, args); - } - - /// - public Page Page(long page, long itemsPerPage, Sql sql) - => Page(page, itemsPerPage, sql.SQL, sql.Arguments); - - /// - public Page Page(long page, long itemsPerPage, Sql sqlCount, Sql sqlPage) - => Page(page, itemsPerPage, sqlCount.SQL, sqlCount.Arguments, sqlPage.SQL, sqlPage.Arguments); - #if ASYNC - - /// - public async Task> PageAsync(CancellationToken cancellationToken, long page, long itemsPerPage, string sqlCount, object[] countArgs, - string sqlPage, object[] pageArgs) + /// + public async Task> PageAsync(CancellationToken cancellationToken, long page, long itemsPerPage, string sqlCount, object[] countArgs, string sqlPage, object[] pageArgs) { var saveTimeout = OneTimeCommandTimeout; @@ -1259,61 +1542,21 @@ public async Task> PageAsync(CancellationToken cancellationToken, lon return result; } - - /// - public Task> PageAsync(long page, long itemsPerPage, string sqlCount, object[] countArgs, string sqlPage, object[] pageArgs) - => PageAsync(CancellationToken.None, page, itemsPerPage, sqlCount, countArgs, sqlPage, pageArgs); - - /// - public Task> PageAsync(CancellationToken cancellationToken, long page, long itemsPerPage) - => PageAsync(cancellationToken, page, itemsPerPage, string.Empty); - - /// - public Task> PageAsync(long page, long itemsPerPage) - => PageAsync(CancellationToken.None, page, itemsPerPage, string.Empty); - - /// - public Task> PageAsync(CancellationToken cancellationToken, long page, long itemsPerPage, string sql, params object[] args) - { - BuildPageQueries((page - 1) * itemsPerPage, itemsPerPage, sql, ref args, out var sqlCount, out var sqlPage); - return PageAsync(cancellationToken, page, itemsPerPage, sqlCount, args, sqlPage, args); - } - - /// - public Task> PageAsync(long page, long itemsPerPage, string sql, params object[] args) - => PageAsync(CancellationToken.None, page, itemsPerPage, sql, args); - - /// - public Task> PageAsync(CancellationToken cancellationToken, long page, long itemsPerPage, Sql sql) - => PageAsync(cancellationToken, page, itemsPerPage, sql.SQL, sql.Arguments); - - /// - public Task> PageAsync(long page, long itemsPerPage, Sql sql) - => PageAsync(CancellationToken.None, page, itemsPerPage, sql.SQL, sql.Arguments); - - /// - public Task> PageAsync(CancellationToken cancellationToken, long page, long itemsPerPage, Sql sqlCount, Sql sqlPage) - => PageAsync(cancellationToken, page, itemsPerPage, sqlCount.SQL, sqlCount.Arguments, sqlPage.SQL, sqlPage.Arguments); - - /// - public Task> PageAsync(long page, long itemsPerPage, Sql sqlCount, Sql sqlPage) - => PageAsync(CancellationToken.None, page, itemsPerPage, sqlCount.SQL, sqlCount.Arguments, sqlPage.SQL, sqlPage.Arguments); - #endif -#endregion + #endregion -#region operation: SkipTake + #region SkipTake, SkipTakeAsync - /// + /// public List SkipTake(long skip, long take) => SkipTake(skip, take, string.Empty); - /// + /// public List SkipTake(long skip, long take, Sql sql) => SkipTake(skip, take, sql.SQL, sql.Arguments); - /// + /// public List SkipTake(long skip, long take, string sql, params object[] args) { BuildPageQueries(skip, take, sql, ref args, out var sqlCount, out var sqlPage); @@ -1321,509 +1564,280 @@ public List SkipTake(long skip, long take, string sql, params object[] arg } #if ASYNC - - /// - public Task> SkipTakeAsync(CancellationToken cancellationToken, long skip, long take) - => SkipTakeAsync(cancellationToken, skip, take, string.Empty); - - /// + /// public Task> SkipTakeAsync(long skip, long take) => SkipTakeAsync(CancellationToken.None, skip, take, string.Empty); - /// - public Task> SkipTakeAsync(CancellationToken cancellationToken, long skip, long take, string sql, params object[] args) - { - BuildPageQueries(skip, take, sql, ref args, out var sqlCount, out var sqlPage); - return FetchAsync(cancellationToken, sqlPage, args); - } + /// + public Task> SkipTakeAsync(long skip, long take, Sql sql) + => SkipTakeAsync(skip, take, sql.SQL, sql.Arguments); - /// + /// public Task> SkipTakeAsync(long skip, long take, string sql, params object[] args) => SkipTakeAsync(CancellationToken.None, skip, take, sql, args); - /// + /// + public Task> SkipTakeAsync(CancellationToken cancellationToken, long skip, long take) + => SkipTakeAsync(cancellationToken, skip, take, string.Empty); + + /// public Task> SkipTakeAsync(CancellationToken cancellationToken, long skip, long take, Sql sql) => SkipTakeAsync(cancellationToken, skip, take, sql.SQL, sql.Arguments); - /// - public Task> SkipTakeAsync(long skip, long take, Sql sql) - => SkipTakeAsync(skip, take, sql.SQL, sql.Arguments); - + /// + public Task> SkipTakeAsync(CancellationToken cancellationToken, long skip, long take, string sql, params object[] args) + { + BuildPageQueries(skip, take, sql, ref args, out var sqlCount, out var sqlPage); + return FetchAsync(cancellationToken, sqlPage, args); + } #endif -#endregion - -#region operation: Query - - /// - public IEnumerable Query() - => Query(string.Empty); + #endregion - /// - public IEnumerable Query(string sql, params object[] args) + /// + /// Starting with a regular SELECT statement, derives the SQL statements required to query a DB for a page of records and the total number of records. + /// + /// The Type representing a row in the result set. + /// The number of rows to skip before the start of the page. + /// The number of rows in the page. + /// The original SQL select statement. + /// Arguments to any embedded parameters in the SQL. + /// Outputs the SQL statement to query for the total number of matching rows. + /// Outputs the SQL statement to retrieve a single page of matching rows. + /// Thrown when unable to parse the given statement. + protected virtual void BuildPageQueries(long skip, long take, string sql, ref object[] args, out string sqlCount, out string sqlPage) { if (EnableAutoSelect) sql = AutoSelectHelper.AddSelectClause(_provider, sql, _defaultMapper); - return ExecuteReader(CommandType.Text, sql, args); + SQLParts parts; + if (!Provider.PagingUtility.SplitSQL(sql, out parts)) + throw new Exception("Unable to parse SQL statement for paged query"); + + sqlPage = _provider.BuildPageQuery(skip, take, parts, ref args); + sqlCount = parts.SqlCount; } - /// - public IEnumerable Query(Sql sql) - => Query(sql.SQL, sql.Arguments); + #region Exists, ExistsAsync -#if ASYNC - /// - public Task QueryAsync(Action receivePocoCallback) - => QueryAsync(receivePocoCallback, CancellationToken.None, CommandType.Text, string.Empty); + /// + public bool Exists(object primaryKey) + { + var poco = PocoData.ForType(typeof(T), _defaultMapper); + return Exists($"{_provider.EscapeSqlIdentifier(poco.TableInfo.PrimaryKey)}=@0", + primaryKey is T ? poco.Columns[poco.TableInfo.PrimaryKey].GetValue(primaryKey) : primaryKey); + } - /// - public Task QueryAsync(Action receivePocoCallback, CommandType commandType) - => QueryAsync(receivePocoCallback, CancellationToken.None, commandType, string.Empty); + /// + public bool Exists(string sqlCondition, params object[] args) + { + var poco = PocoData.ForType(typeof(T), _defaultMapper).TableInfo; - /// - public Task QueryAsync(Action receivePocoCallback, CancellationToken cancellationToken) - => QueryAsync(receivePocoCallback, cancellationToken, CommandType.Text, string.Empty); + if (sqlCondition.TrimStart().StartsWith("where", StringComparison.OrdinalIgnoreCase)) + sqlCondition = sqlCondition.TrimStart().Substring(5); - /// - public Task QueryAsync(Action receivePocoCallback, CancellationToken cancellationToken, CommandType commandType) - => QueryAsync(receivePocoCallback, cancellationToken, commandType, string.Empty); + return ExecuteScalar(string.Format(_provider.GetExistsSql(), Provider.EscapeTableName(poco.TableName), sqlCondition), args) != 0; + } - /// - public Task QueryAsync(Action receivePocoCallback, string sql, params object[] args) - => QueryAsync(receivePocoCallback, CancellationToken.None, CommandType.Text, sql, args); +#if ASYNC + public Task ExistsAsync(object primaryKey) + => ExistsAsync(CancellationToken.None, primaryKey); - /// - public Task QueryAsync(Action receivePocoCallback, CommandType commandType, string sql, params object[] args) - => QueryAsync(receivePocoCallback, CancellationToken.None, commandType, sql, args); + public Task ExistsAsync(string sqlCondition, params object[] args) + => ExistsAsync(CancellationToken.None, sqlCondition, args); - /// - public Task QueryAsync(Action receivePocoCallback, CancellationToken cancellationToken, string sql, params object[] args) - => QueryAsync(receivePocoCallback, CancellationToken.None, CommandType.Text, sql, args); + public Task ExistsAsync(CancellationToken cancellationToken, object primaryKey) + { + var poco = PocoData.ForType(typeof(T), _defaultMapper); + return ExistsAsync(cancellationToken, $"{_provider.EscapeSqlIdentifier(poco.TableInfo.PrimaryKey)}=@0", + primaryKey is T ? poco.Columns[poco.TableInfo.PrimaryKey].GetValue(primaryKey) : primaryKey); + } - /// - public Task QueryAsync(Action receivePocoCallback, CancellationToken cancellationToken, CommandType commandType, string sql, params object[] args) + public async Task ExistsAsync(CancellationToken cancellationToken, string sqlCondition, params object[] args) { - if (EnableAutoSelect) - sql = AutoSelectHelper.AddSelectClause(_provider, sql, _defaultMapper); - return ExecuteReaderAsync(receivePocoCallback, cancellationToken, commandType, sql, args); + var poco = PocoData.ForType(typeof(T), _defaultMapper).TableInfo; + + if (sqlCondition.TrimStart().StartsWith("where", StringComparison.OrdinalIgnoreCase)) + sqlCondition = sqlCondition.TrimStart().Substring(5); + + return await ExecuteScalarAsync(cancellationToken, + string.Format(_provider.GetExistsSql(), Provider.EscapeTableName(poco.TableName), sqlCondition), args).ConfigureAwait(false) != 0; } +#endif - /// - public Task QueryAsync(Action receivePocoCallback, Sql sql) - => QueryAsync(receivePocoCallback, CancellationToken.None, CommandType.Text, sql.SQL, sql.Arguments); + #endregion - /// - public Task QueryAsync(Action receivePocoCallback, CommandType commandType, Sql sql) - => QueryAsync(receivePocoCallback, CancellationToken.None, commandType, sql.SQL, sql.Arguments); + #region Single, SingleAsync - /// - public Task QueryAsync(Action receivePocoCallback, CancellationToken cancellationToken, Sql sql) - => QueryAsync(receivePocoCallback, cancellationToken, CommandType.Text, sql.SQL, sql.Arguments); + /// + public T Single(object primaryKey) + => Single(GenerateSingleByKeySql(primaryKey)); - /// - public Task QueryAsync(Action receivePocoCallback, CancellationToken cancellationToken, CommandType commandType, Sql sql) - => QueryAsync(receivePocoCallback, cancellationToken, commandType, sql.SQL, sql.Arguments); + /// + public T Single(Sql sql) + => Query(sql).Single(); - /// - public Task> QueryAsync() - => QueryAsync(CancellationToken.None, CommandType.Text, string.Empty); + /// + public T Single(string sql, params object[] args) + => Query(sql, args).Single(); - /// - public Task> QueryAsync(CommandType commandType) - => QueryAsync(CancellationToken.None, commandType, string.Empty); +#if ASYNC + /// + public Task SingleAsync(object primaryKey) + => SingleAsync(CancellationToken.None, primaryKey); - /// - public Task> QueryAsync(CancellationToken cancellationToken) - => QueryAsync(cancellationToken, CommandType.Text, string.Empty); + /// + public Task SingleAsync(Sql sql) + => SingleAsync(CancellationToken.None, sql); - /// - public Task> QueryAsync(CancellationToken cancellationToken, CommandType commandType) - => QueryAsync(cancellationToken, commandType, string.Empty); + /// + public Task SingleAsync(string sql, params object[] args) + => SingleAsync(CancellationToken.None, sql, args); - /// - public Task> QueryAsync(string sql, params object[] args) - => QueryAsync(CancellationToken.None, CommandType.Text, sql, args); + /// + public Task SingleAsync(CancellationToken cancellationToken, object primaryKey) + => SingleAsync(cancellationToken, GenerateSingleByKeySql(primaryKey)); - /// - public Task> QueryAsync(CommandType commandType, string sql, params object[] args) - => QueryAsync(CancellationToken.None, commandType, sql, args); + /// + public Task SingleAsync(CancellationToken cancellationToken, Sql sql) + => SingleAsync(cancellationToken, sql.SQL, sql.Arguments); - /// - public Task> QueryAsync(CancellationToken cancellationToken, string sql, params object[] args) - => QueryAsync(CancellationToken.None, CommandType.Text, sql, args); + /// + public async Task SingleAsync(CancellationToken cancellationToken, string sql, params object[] args) + => (await FetchAsync(cancellationToken, sql, args).ConfigureAwait(false)).Single(); +#endif - /// - public Task> QueryAsync(CancellationToken cancellationToken, CommandType commandType, string sql, params object[] args) - { - if (EnableAutoSelect) - sql = AutoSelectHelper.AddSelectClause(_provider, sql, _defaultMapper); + #endregion - return ExecuteReaderAsync(cancellationToken, commandType, sql, args); - } + #region SingleOrDefault, SingleOrDefaultAsync - /// - public Task> QueryAsync(Sql sql) - => QueryAsync(CancellationToken.None, CommandType.Text, sql.SQL, sql.Arguments); + /// + public T SingleOrDefault(object primaryKey) + => SingleOrDefault(GenerateSingleByKeySql(primaryKey)); - /// - public Task> QueryAsync(CommandType commandType, Sql sql) - => QueryAsync(CancellationToken.None, commandType, sql.SQL, sql.Arguments); + /// + public T SingleOrDefault(Sql sql) + => Query(sql).SingleOrDefault(); - /// - public Task> QueryAsync(CancellationToken cancellationToken, Sql sql) - => QueryAsync(cancellationToken, CommandType.Text, sql.SQL, sql.Arguments); + /// + public T SingleOrDefault(string sql, params object[] args) + => Query(sql, args).SingleOrDefault(); - /// - public Task> QueryAsync(CancellationToken cancellationToken, CommandType commandType, Sql sql) - => QueryAsync(cancellationToken, commandType, sql.SQL, sql.Arguments); +#if ASYNC + /// + public Task SingleOrDefaultAsync(object primaryKey) + => SingleOrDefaultAsync(CancellationToken.None, primaryKey); - protected virtual async Task ExecuteReaderAsync(Action processPoco, CancellationToken cancellationToken, CommandType commandType, string sql, - object[] args) - { - await OpenSharedConnectionAsync(cancellationToken).ConfigureAwait(false); - try - { - using (var cmd = CreateCommand(_sharedConnection, commandType, sql, args)) - { - IDataReader reader; - var pd = PocoData.ForType(typeof(T), _defaultMapper); + /// + public Task SingleOrDefaultAsync(Sql sql) + => SingleOrDefaultAsync(CancellationToken.None, sql); - try - { - reader = await ExecuteReaderHelperAsync(cancellationToken, cmd).ConfigureAwait(false); - } - catch (Exception e) - { - if (OnException(e)) - throw; - return; - } + /// + public Task SingleOrDefaultAsync(string sql, params object[] args) + => SingleOrDefaultAsync(CancellationToken.None, sql, args); - var readerAsync = reader as DbDataReader; - var factory = - pd.GetFactory(cmd.CommandText, _sharedConnection.ConnectionString, 0, reader.FieldCount, reader, - _defaultMapper) as Func; + /// + public Task SingleOrDefaultAsync(CancellationToken cancellationToken, object primaryKey) + => SingleOrDefaultAsync(cancellationToken, GenerateSingleByKeySql(primaryKey)); - using (reader) - { - while (true) - { - T poco; - try - { - if (readerAsync != null) - { - if (!await readerAsync.ReadAsync(cancellationToken).ConfigureAwait(false)) - return; - } - else - { - if (!reader.Read()) - return; - } + /// + public Task SingleOrDefaultAsync(CancellationToken cancellationToken, Sql sql) + => SingleOrDefaultAsync(cancellationToken, sql.SQL, sql.Arguments); - poco = factory(reader); - processPoco(poco); - } - catch (Exception e) - { - if (OnException(e)) - throw; - return; - } - } - } - } - } - finally - { - CloseSharedConnection(); - } - } + /// + public async Task SingleOrDefaultAsync(CancellationToken cancellationToken, string sql, params object[] args) + => (await FetchAsync(cancellationToken, sql, args).ConfigureAwait(false)).SingleOrDefault(); +#endif - protected virtual async Task> ExecuteReaderAsync(CancellationToken cancellationToken, CommandType commandType, string sql, - object[] args) + private Sql GenerateSingleByKeySql(object primaryKey) { - await OpenSharedConnectionAsync(cancellationToken).ConfigureAwait(false); - var cmd = CreateCommand(_sharedConnection, commandType, sql, args); - IDataReader reader = null; - var pd = PocoData.ForType(typeof(T), _defaultMapper); - - try - { - reader = await ExecuteReaderHelperAsync(cancellationToken, cmd).ConfigureAwait(false); - } - catch (Exception e) - { - if (OnException(e)) - throw; - try - { - cmd?.Dispose(); - reader?.Dispose(); - } - catch - { - // ignored - } - - return AsyncReader.Empty(); - } - - var factory = - pd.GetFactory(cmd.CommandText, _sharedConnection.ConnectionString, 0, reader.FieldCount, reader, _defaultMapper) as Func; - - return new AsyncReader(this, cmd, reader, factory); - } - -#endif - - protected virtual IEnumerable ExecuteReader(CommandType commandType, string sql, params object[] args) - { - OpenSharedConnection(); - try - { - using (var cmd = CreateCommand(_sharedConnection, commandType, sql, args)) - { - IDataReader r; - var pd = PocoData.ForType(typeof(T), _defaultMapper); - try - { - r = ExecuteReaderHelper(cmd); - } - catch (Exception x) - { - if (OnException(x)) - throw; - yield break; - } - - var factory = pd.GetFactory(cmd.CommandText, _sharedConnection.ConnectionString, 0, r.FieldCount, r, - _defaultMapper) as Func; - using (r) - { - while (true) - { - T poco; - try - { - if (!r.Read()) - yield break; - poco = factory(r); - } - catch (Exception x) - { - if (OnException(x)) - throw; - yield break; - } - - yield return poco; - } - } - } - } - finally - { - CloseSharedConnection(); - } - } - -#endregion - -#region operation: Exists - - /// - public bool Exists(string sqlCondition, params object[] args) - { - var poco = PocoData.ForType(typeof(T), _defaultMapper).TableInfo; - - if (sqlCondition.TrimStart().StartsWith("where", StringComparison.OrdinalIgnoreCase)) - sqlCondition = sqlCondition.TrimStart().Substring(5); - - return ExecuteScalar(string.Format(_provider.GetExistsSql(), Provider.EscapeTableName(poco.TableName), sqlCondition), args) != 0; - } - - /// - public bool Exists(object primaryKey) - { - var poco = PocoData.ForType(typeof(T), _defaultMapper); - return Exists($"{_provider.EscapeSqlIdentifier(poco.TableInfo.PrimaryKey)}=@0", - primaryKey is T ? poco.Columns[poco.TableInfo.PrimaryKey].GetValue(primaryKey) : primaryKey); - } - -#if ASYNC - public Task ExistsAsync(object primaryKey) - => ExistsAsync(CancellationToken.None, primaryKey); - - public Task ExistsAsync(CancellationToken cancellationToken, object primaryKey) - { - var poco = PocoData.ForType(typeof(T), _defaultMapper); - return ExistsAsync(cancellationToken, $"{_provider.EscapeSqlIdentifier(poco.TableInfo.PrimaryKey)}=@0", - primaryKey is T ? poco.Columns[poco.TableInfo.PrimaryKey].GetValue(primaryKey) : primaryKey); - } - - public Task ExistsAsync(string sqlCondition, params object[] args) - => ExistsAsync(CancellationToken.None, sqlCondition, args); - - public async Task ExistsAsync(CancellationToken cancellationToken, string sqlCondition, params object[] args) - { - var poco = PocoData.ForType(typeof(T), _defaultMapper).TableInfo; + string pkName = _provider.EscapeSqlIdentifier(PocoData.ForType(typeof(T), _defaultMapper).TableInfo.PrimaryKey); + var sql = $"WHERE {pkName} = @0"; - if (sqlCondition.TrimStart().StartsWith("where", StringComparison.OrdinalIgnoreCase)) - sqlCondition = sqlCondition.TrimStart().Substring(5); + if (!EnableAutoSelect) + // We're going to be nice and add the SELECT anyway + sql = AutoSelectHelper.AddSelectClause(_provider, sql, _defaultMapper); - return await ExecuteScalarAsync(cancellationToken, - string.Format(_provider.GetExistsSql(), Provider.EscapeTableName(poco.TableName), sqlCondition), args).ConfigureAwait(false) != 0; + return new Sql(sql, primaryKey); } -#endif - -#endregion - -#region operation: Linq style (Exists, Single, SingleOrDefault, First, FirstOrDefault, etc...) - - /// - public T Single(object primaryKey) - => Single(GenerateSingleByKeySql(primaryKey)); - - /// - public T SingleOrDefault(object primaryKey) - => SingleOrDefault(GenerateSingleByKeySql(primaryKey)); - - /// - public T Single(string sql, params object[] args) - => Query(sql, args).Single(); - - /// - public T SingleOrDefault(string sql, params object[] args) - => Query(sql, args).SingleOrDefault(); - /// - public T First(string sql, params object[] args) - => Query(sql, args).First(); - - /// - public T FirstOrDefault(string sql, params object[] args) - => Query(sql, args).FirstOrDefault(); - - /// - public T Single(Sql sql) - => Query(sql).Single(); + #endregion - /// - public T SingleOrDefault(Sql sql) - => Query(sql).SingleOrDefault(); + #region First, FirstAsync - /// + /// public T First(Sql sql) => Query(sql).First(); - /// - public T FirstOrDefault(Sql sql) - => Query(sql).FirstOrDefault(); + /// + public T First(string sql, params object[] args) + => Query(sql, args).First(); #if ASYNC + /// + public Task FirstAsync(Sql sql) + => FirstAsync(CancellationToken.None, sql); - /// - public Task SingleAsync(object primaryKey) - => SingleAsync(CancellationToken.None, primaryKey); - - /// - public Task SingleAsync(CancellationToken cancellationToken, object primaryKey) - => SingleAsync(cancellationToken, GenerateSingleByKeySql(primaryKey)); - - /// - public Task SingleAsync(string sql, params object[] args) - => SingleAsync(CancellationToken.None, sql, args); - - /// - public async Task SingleAsync(CancellationToken cancellationToken, string sql, params object[] args) - => (await FetchAsync(cancellationToken, sql, args).ConfigureAwait(false)).Single(); - - /// - public Task SingleAsync(Sql sql) - => SingleAsync(CancellationToken.None, sql); - - /// - public Task SingleAsync(CancellationToken cancellationToken, Sql sql) - => SingleAsync(cancellationToken, sql.SQL, sql.Arguments); - - /// - public Task SingleOrDefaultAsync(Sql sql) - => SingleOrDefaultAsync(CancellationToken.None, sql); - - /// - public Task SingleOrDefaultAsync(CancellationToken cancellationToken, Sql sql) - => SingleOrDefaultAsync(cancellationToken, sql.SQL, sql.Arguments); - - /// - public Task SingleOrDefaultAsync(object primaryKey) - => SingleOrDefaultAsync(CancellationToken.None, primaryKey); - - /// - public Task SingleOrDefaultAsync(CancellationToken cancellationToken, object primaryKey) - => SingleOrDefaultAsync(cancellationToken, GenerateSingleByKeySql(primaryKey)); - - /// - public Task SingleOrDefaultAsync(string sql, params object[] args) - => SingleOrDefaultAsync(CancellationToken.None, sql, args); - - /// - public async Task SingleOrDefaultAsync(CancellationToken cancellationToken, string sql, params object[] args) - => (await FetchAsync(cancellationToken, sql, args).ConfigureAwait(false)).SingleOrDefault(); - - /// + /// public Task FirstAsync(string sql, params object[] args) => FirstAsync(CancellationToken.None, sql, args); - /// + /// + public Task FirstAsync(CancellationToken cancellationToken, Sql sql) + => FirstAsync(cancellationToken, sql.SQL, sql.Arguments); + + /// public async Task FirstAsync(CancellationToken cancellationToken, string sql, params object[] args) => (await FetchAsync(cancellationToken, sql, args).ConfigureAwait(false)).First(); +#endif - /// - public Task FirstAsync(Sql sql) - => FirstAsync(CancellationToken.None, sql); + #endregion - /// - public Task FirstAsync(CancellationToken cancellationToken, Sql sql) - => FirstAsync(cancellationToken, sql.SQL, sql.Arguments); + #region FirstOrDefault, FirstOrDefaultAsync - /// - public Task FirstOrDefaultAsync(string sql, params object[] args) - => FirstOrDefaultAsync(CancellationToken.None, sql, args); + /// + public T FirstOrDefault(Sql sql) + => Query(sql).FirstOrDefault(); - /// - public async Task FirstOrDefaultAsync(CancellationToken cancellationToken, string sql, params object[] args) - => (await FetchAsync(cancellationToken, sql, args).ConfigureAwait(false)).FirstOrDefault(); + /// + public T FirstOrDefault(string sql, params object[] args) + => Query(sql, args).FirstOrDefault(); - /// +#if ASYNC + /// public Task FirstOrDefaultAsync(Sql sql) => FirstOrDefaultAsync(CancellationToken.None, sql); - /// + /// + public Task FirstOrDefaultAsync(string sql, params object[] args) + => FirstOrDefaultAsync(CancellationToken.None, sql, args); + + /// public Task FirstOrDefaultAsync(CancellationToken cancellationToken, Sql sql) => FirstOrDefaultAsync(cancellationToken, sql.SQL, sql.Arguments); + /// + public async Task FirstOrDefaultAsync(CancellationToken cancellationToken, string sql, params object[] args) + => (await FetchAsync(cancellationToken, sql, args).ConfigureAwait(false)).FirstOrDefault(); #endif - private Sql GenerateSingleByKeySql(object primaryKey) - { - string pkName = _provider.EscapeSqlIdentifier(PocoData.ForType(typeof(T), _defaultMapper).TableInfo.PrimaryKey); - var sql = $"WHERE {pkName} = @0"; - - if (!EnableAutoSelect) - // We're going to be nice and add the SELECT anyway - sql = AutoSelectHelper.AddSelectClause(_provider, sql, _defaultMapper); + #endregion - return new Sql(sql, primaryKey); - } + #region Insert, InsertAsync -#endregion + /// + /// Thrown if is null. + public object Insert(object poco) + { + if (poco == null) + throw new ArgumentNullException(nameof(poco)); -#region operation: Insert + var pd = PocoData.ForType(poco.GetType(), _defaultMapper); + return ExecuteInsert(pd.TableInfo.TableName, pd.TableInfo.PrimaryKey, pd.TableInfo.AutoIncrement, poco); + } - /// + /// + /// Thrown when or is null or empty. public object Insert(string tableName, object poco) { if (string.IsNullOrEmpty(tableName)) @@ -1837,7 +1851,7 @@ public object Insert(string tableName, object poco) return ExecuteInsert(tableName, pd == null ? null : pd.TableInfo.PrimaryKey, pd != null && pd.TableInfo.AutoIncrement, poco); } - /// + /// public object Insert(string tableName, string primaryKeyName, object poco) { if (string.IsNullOrEmpty(tableName)) @@ -1857,7 +1871,7 @@ public object Insert(string tableName, string primaryKeyName, object poco) return ExecuteInsert(tableName, primaryKeyName, autoIncrement, poco); } - /// + /// public object Insert(string tableName, string primaryKeyName, bool autoIncrement, object poco) { if (string.IsNullOrEmpty(tableName)) @@ -1872,67 +1886,70 @@ public object Insert(string tableName, string primaryKeyName, bool autoIncrement return ExecuteInsert(tableName, primaryKeyName, autoIncrement, poco); } - /// - /// thrown if is . - public object Insert(object poco) - { - if (poco == null) - throw new ArgumentNullException(nameof(poco)); +#if ASYNC + public Task InsertAsync(object poco) + => InsertAsync(CancellationToken.None, poco); + + public Task InsertAsync(string tableName, object poco) + => InsertAsync(CancellationToken.None, tableName, poco); + + public Task InsertAsync(string tableName, string primaryKeyName, object poco) + => InsertAsync(CancellationToken.None, tableName, primaryKeyName, poco); + + public Task InsertAsync(string tableName, string primaryKeyName, bool autoIncrement, object poco) + => InsertAsync(CancellationToken.None, tableName, primaryKeyName, autoIncrement, poco); + + public Task InsertAsync(CancellationToken cancellationToken, object poco) + { + if (poco == null) + throw new ArgumentNullException(nameof(poco)); var pd = PocoData.ForType(poco.GetType(), _defaultMapper); - return ExecuteInsert(pd.TableInfo.TableName, pd.TableInfo.PrimaryKey, pd.TableInfo.AutoIncrement, poco); + return ExecuteInsertAsync(cancellationToken, pd.TableInfo.TableName, pd.TableInfo.PrimaryKey, pd.TableInfo.AutoIncrement, poco); } - private object ExecuteInsert(string tableName, string primaryKeyName, bool autoIncrement, object poco) + public Task InsertAsync(CancellationToken cancellationToken, string tableName, object poco) { - try - { - OpenSharedConnection(); - try - { - using (var cmd = CreateCommand(_sharedConnection, string.Empty)) - { - var pd = PocoData.ForObject(poco, primaryKeyName, _defaultMapper); - var names = new List(); - var values = new List(); + if (tableName == null) + throw new ArgumentNullException(nameof(tableName)); + if (poco == null) + throw new ArgumentNullException(nameof(poco)); - PrepareExecuteInsert(tableName, primaryKeyName, autoIncrement, poco, pd, names, values, cmd); + var pd = PocoData.ForType(poco.GetType(), _defaultMapper); + return ExecuteInsertAsync(cancellationToken, tableName, pd?.TableInfo.PrimaryKey, pd != null && pd.TableInfo.AutoIncrement, poco); + } - if (!autoIncrement) - { - ExecuteNonQueryHelper(cmd); + public Task InsertAsync(CancellationToken cancellationToken, string tableName, string primaryKeyName, object poco) + { + if (tableName == null) + throw new ArgumentNullException(nameof(tableName)); + if (primaryKeyName == null) + throw new ArgumentNullException(nameof(primaryKeyName)); + if (poco == null) + throw new ArgumentNullException(nameof(poco)); - if (primaryKeyName != null && pd.Columns.TryGetValue(primaryKeyName, out var pkColumn)) - return pkColumn.GetValue(poco); - else - return null; - } + var t = poco.GetType(); + var pd = PocoData.ForType(poco.GetType(), _defaultMapper); + var autoIncrement = pd == null || pd.TableInfo.AutoIncrement || t.Name.Contains("AnonymousType") && + !t.GetProperties().Any(p => p.Name.Equals(primaryKeyName, StringComparison.OrdinalIgnoreCase)); - var id = _provider.ExecuteInsert(this, cmd, primaryKeyName); + return ExecuteInsertAsync(cancellationToken, tableName, primaryKeyName, autoIncrement, poco); + } - // Assign the ID back to the primary key property - if (primaryKeyName != null && !poco.GetType().Name.Contains("AnonymousType")) - if (pd.Columns.TryGetValue(primaryKeyName, out var pc)) - pc.SetValue(poco, pc.ChangeType(id)); + public Task InsertAsync(CancellationToken cancellationToken, string tableName, string primaryKeyName, bool autoIncrement, object poco) + { + if (tableName == null) + throw new ArgumentNullException(nameof(tableName)); + if (primaryKeyName == null) + throw new ArgumentNullException(nameof(primaryKeyName)); + if (poco == null) + throw new ArgumentNullException(nameof(poco)); - return id; - } - } - finally - { - CloseSharedConnection(); - } - } - catch (Exception x) - { - if (OnException(x)) - throw; - return null; - } + return ExecuteInsertAsync(cancellationToken, tableName, primaryKeyName, autoIncrement, poco); } +#endif - private void PrepareExecuteInsert(string tableName, string primaryKeyName, bool autoIncrement, object poco, PocoData pd, List names, - List values, IDbCommand cmd) + private void PrepareExecuteInsert(string tableName, string primaryKeyName, bool autoIncrement, object poco, PocoData pd, List names, List values, IDbCommand cmd) { var index = 0; foreach (var i in pd.Columns) @@ -1968,71 +1985,56 @@ private void PrepareExecuteInsert(string tableName, string primaryKeyName, bool $"INSERT INTO {_provider.EscapeTableName(tableName)} ({string.Join(",", names.ToArray())}){outputClause} VALUES ({string.Join(",", values.ToArray())})"; } -#if ASYNC - - public Task InsertAsync(string tableName, object poco) - => InsertAsync(CancellationToken.None, tableName, poco); - - public Task InsertAsync(CancellationToken cancellationToken, string tableName, object poco) - { - if (tableName == null) - throw new ArgumentNullException(nameof(tableName)); - if (poco == null) - throw new ArgumentNullException(nameof(poco)); - - var pd = PocoData.ForType(poco.GetType(), _defaultMapper); - return ExecuteInsertAsync(cancellationToken, tableName, pd?.TableInfo.PrimaryKey, pd != null && pd.TableInfo.AutoIncrement, poco); - } - - public Task InsertAsync(string tableName, string primaryKeyName, object poco) - => InsertAsync(CancellationToken.None, tableName, primaryKeyName, poco); - - public Task InsertAsync(CancellationToken cancellationToken, string tableName, string primaryKeyName, object poco) + private object ExecuteInsert(string tableName, string primaryKeyName, bool autoIncrement, object poco) { - if (tableName == null) - throw new ArgumentNullException(nameof(tableName)); - if (primaryKeyName == null) - throw new ArgumentNullException(nameof(primaryKeyName)); - if (poco == null) - throw new ArgumentNullException(nameof(poco)); - - var t = poco.GetType(); - var pd = PocoData.ForType(poco.GetType(), _defaultMapper); - var autoIncrement = pd == null || pd.TableInfo.AutoIncrement || t.Name.Contains("AnonymousType") && - !t.GetProperties().Any(p => p.Name.Equals(primaryKeyName, StringComparison.OrdinalIgnoreCase)); - - return ExecuteInsertAsync(cancellationToken, tableName, primaryKeyName, autoIncrement, poco); - } + try + { + OpenSharedConnection(); + try + { + using (var cmd = CreateCommand(_sharedConnection, string.Empty)) + { + var pd = PocoData.ForObject(poco, primaryKeyName, _defaultMapper); + var names = new List(); + var values = new List(); - public Task InsertAsync(string tableName, string primaryKeyName, bool autoIncrement, object poco) - => InsertAsync(CancellationToken.None, tableName, primaryKeyName, autoIncrement, poco); + PrepareExecuteInsert(tableName, primaryKeyName, autoIncrement, poco, pd, names, values, cmd); - public Task InsertAsync(CancellationToken cancellationToken, string tableName, string primaryKeyName, bool autoIncrement, object poco) - { - if (tableName == null) - throw new ArgumentNullException(nameof(tableName)); - if (primaryKeyName == null) - throw new ArgumentNullException(nameof(primaryKeyName)); - if (poco == null) - throw new ArgumentNullException(nameof(poco)); + if (!autoIncrement) + { + ExecuteNonQueryHelper(cmd); - return ExecuteInsertAsync(cancellationToken, tableName, primaryKeyName, autoIncrement, poco); - } + if (primaryKeyName != null && pd.Columns.TryGetValue(primaryKeyName, out var pkColumn)) + return pkColumn.GetValue(poco); + else + return null; + } - public Task InsertAsync(object poco) - => InsertAsync(CancellationToken.None, poco); + var id = _provider.ExecuteInsert(this, cmd, primaryKeyName); - public Task InsertAsync(CancellationToken cancellationToken, object poco) - { - if (poco == null) - throw new ArgumentNullException(nameof(poco)); + // Assign the ID back to the primary key property + if (primaryKeyName != null && !poco.GetType().Name.Contains("AnonymousType")) + if (pd.Columns.TryGetValue(primaryKeyName, out var pc)) + pc.SetValue(poco, pc.ChangeType(id)); - var pd = PocoData.ForType(poco.GetType(), _defaultMapper); - return ExecuteInsertAsync(cancellationToken, pd.TableInfo.TableName, pd.TableInfo.PrimaryKey, pd.TableInfo.AutoIncrement, poco); + return id; + } + } + finally + { + CloseSharedConnection(); + } + } + catch (Exception x) + { + if (OnException(x)) + throw; + return null; + } } - private async Task ExecuteInsertAsync(CancellationToken cancellationToken, string tableName, string primaryKeyName, bool autoIncrement, - object poco) +#if ASYNC + private async Task ExecuteInsertAsync(CancellationToken cancellationToken, string tableName, string primaryKeyName, bool autoIncrement, object poco) { try { @@ -2079,113 +2081,204 @@ private async Task ExecuteInsertAsync(CancellationToken cancellationToke return null; } } - #endif -#endregion + #endregion -#region operation: Update + #region Update, UpdateAsync - /// - public int Update(string tableName, string primaryKeyName, object poco, object primaryKeyValue) - => Update(tableName, primaryKeyName, poco, primaryKeyValue, null); + /// + public int Update(object poco) + => Update(poco, null, null); - /// - public int Update(string tableName, string primaryKeyName, object poco, object primaryKeyValue, IEnumerable columns) - { - if (string.IsNullOrEmpty(tableName)) - throw new ArgumentNullException(nameof(tableName)); + /// + public int Update(object poco, IEnumerable columns) + => Update(poco, null, columns); - if (string.IsNullOrEmpty(primaryKeyName)) - throw new ArgumentNullException(nameof(primaryKeyName)); + /// + public int Update(object poco, object primaryKeyValue) + => Update(poco, primaryKeyValue, null); + /// + public int Update(object poco, object primaryKeyValue, IEnumerable columns) + { if (poco == null) throw new ArgumentNullException(nameof(poco)); if (columns?.Any() == false) return 0; - return ExecuteUpdate(tableName, primaryKeyName, poco, primaryKeyValue, columns); + var pd = PocoData.ForType(poco.GetType(), _defaultMapper); + return ExecuteUpdate(pd.TableInfo.TableName, pd.TableInfo.PrimaryKey, poco, primaryKeyValue, columns); } - /// + /// public int Update(string tableName, string primaryKeyName, object poco) - => Update(tableName, primaryKeyName, poco, null, null); + => Update(tableName, primaryKeyName, poco, null); - /// + /// public int Update(string tableName, string primaryKeyName, object poco, IEnumerable columns) => Update(tableName, primaryKeyName, poco, null, columns); - /// - public int Update(object poco, IEnumerable columns) - => Update(poco, null, columns); + /// + public int Update(string tableName, string primaryKeyName, object poco, object primaryKeyValue) + => Update(tableName, primaryKeyName, poco, primaryKeyValue, null); - /// - public int Update(object poco) - => Update(poco, null, null); + /// + /// Thrown when , , or is null or empty. + public int Update(string tableName, string primaryKeyName, object poco, object primaryKeyValue, IEnumerable columns) + { + if (string.IsNullOrEmpty(tableName)) + throw new ArgumentNullException(nameof(tableName)); - /// - public int Update(object poco, object primaryKeyValue) - => Update(poco, primaryKeyValue, null); + if (string.IsNullOrEmpty(primaryKeyName)) + throw new ArgumentNullException(nameof(primaryKeyName)); - /// - public int Update(object poco, object primaryKeyValue, IEnumerable columns) - { if (poco == null) throw new ArgumentNullException(nameof(poco)); if (columns?.Any() == false) return 0; - var pd = PocoData.ForType(poco.GetType(), _defaultMapper); - return ExecuteUpdate(pd.TableInfo.TableName, pd.TableInfo.PrimaryKey, poco, primaryKeyValue, columns); + return ExecuteUpdate(tableName, primaryKeyName, poco, primaryKeyValue, columns); } - /// - public int Update(string sql, params object[] args) + /// + public int Update(Sql sql) { - if (string.IsNullOrEmpty(sql)) + if (sql == null) throw new ArgumentNullException(nameof(sql)); var pd = PocoData.ForType(typeof(T), _defaultMapper); - return Execute($"UPDATE {_provider.EscapeTableName(pd.TableInfo.TableName)} {sql}", args); + return Execute(new Sql($"UPDATE {_provider.EscapeTableName(pd.TableInfo.TableName)}").Append(sql)); } - /// - public int Update(Sql sql) + /// + public int Update(string sql, params object[] args) { - if (sql == null) + if (string.IsNullOrEmpty(sql)) throw new ArgumentNullException(nameof(sql)); var pd = PocoData.ForType(typeof(T), _defaultMapper); - return Execute(new Sql($"UPDATE {_provider.EscapeTableName(pd.TableInfo.TableName)}").Append(sql)); + return Execute($"UPDATE {_provider.EscapeTableName(pd.TableInfo.TableName)} {sql}", args); } - private int ExecuteUpdate(string tableName, string primaryKeyName, object poco, object primaryKeyValue, IEnumerable columns) - { - try - { - OpenSharedConnection(); - try - { - using (var cmd = CreateCommand(_sharedConnection, string.Empty)) - { - PreExecuteUpdate(tableName, primaryKeyName, poco, primaryKeyValue, columns, cmd); - return ExecuteNonQueryHelper(cmd); - } - } - finally - { - CloseSharedConnection(); - } - } - catch (Exception x) - { - if (OnException(x)) - throw; - return -1; - } +#if ASYNC + /// + public Task UpdateAsync(object poco) + => UpdateAsync(CancellationToken.None, poco); + + /// + public Task UpdateAsync(object poco, IEnumerable columns) + => UpdateAsync(CancellationToken.None, poco, columns); + + /// + public Task UpdateAsync(object poco, object primaryKeyValue) + => UpdateAsync(CancellationToken.None, poco, primaryKeyValue); + + /// + public Task UpdateAsync(object poco, object primaryKeyValue, IEnumerable columns) + => UpdateAsync(CancellationToken.None, poco, primaryKeyValue, columns); + + /// + public Task UpdateAsync(string tableName, string primaryKeyName, object poco) + => UpdateAsync(CancellationToken.None, tableName, primaryKeyName, poco); + + /// + public Task UpdateAsync(string tableName, string primaryKeyName, object poco, IEnumerable columns) + => UpdateAsync(CancellationToken.None, tableName, primaryKeyName, poco, columns); + + /// + public Task UpdateAsync(string tableName, string primaryKeyName, object poco, object primaryKeyValue) + => UpdateAsync(CancellationToken.None, tableName, primaryKeyName, poco, primaryKeyValue); + + /// + public Task UpdateAsync(string tableName, string primaryKeyName, object poco, object primaryKeyValue, IEnumerable columns) + => UpdateAsync(CancellationToken.None, tableName, primaryKeyName, poco, primaryKeyValue, columns); + + /// + public Task UpdateAsync(Sql sql) + => UpdateAsync(CancellationToken.None, sql); + + /// + public Task UpdateAsync(string sql, params object[] args) + => UpdateAsync(CancellationToken.None, sql, args); + + /// + public Task UpdateAsync(CancellationToken cancellationToken, object poco) + => UpdateAsync(cancellationToken, poco, null, null); + + /// + public Task UpdateAsync(CancellationToken cancellationToken, object poco, IEnumerable columns) + => UpdateAsync(cancellationToken, poco, null, columns); + + /// + public Task UpdateAsync(CancellationToken cancellationToken, object poco, object primaryKeyValue) + => UpdateAsync(cancellationToken, poco, primaryKeyValue, null); + + /// + public Task UpdateAsync(CancellationToken cancellationToken, object poco, object primaryKeyValue, IEnumerable columns) + { + if (poco == null) + throw new ArgumentNullException(nameof(poco)); + + if (columns?.Any() == false) + return Task.FromResult(0); + + var pd = PocoData.ForType(poco.GetType(), _defaultMapper); + return ExecuteUpdateAsync(cancellationToken, pd.TableInfo.TableName, pd.TableInfo.PrimaryKey, poco, primaryKeyValue, columns); + } + + /// + public Task UpdateAsync(CancellationToken cancellationToken, string tableName, string primaryKeyName, object poco) + => UpdateAsync(cancellationToken, tableName, primaryKeyName, poco, null); + + /// + public Task UpdateAsync(CancellationToken cancellationToken, string tableName, string primaryKeyName, object poco, IEnumerable columns) + => UpdateAsync(cancellationToken, tableName, primaryKeyName, poco, null, columns); + + /// + public Task UpdateAsync(CancellationToken cancellationToken, string tableName, string primaryKeyName, object poco, object primaryKeyValue) + => UpdateAsync(cancellationToken, tableName, primaryKeyName, poco, primaryKeyValue, null); + + /// + public Task UpdateAsync(CancellationToken cancellationToken, string tableName, string primaryKeyName, object poco, object primaryKeyValue, IEnumerable columns) + { + if (string.IsNullOrEmpty(tableName)) + throw new ArgumentNullException(nameof(tableName)); + + if (string.IsNullOrEmpty(primaryKeyName)) + throw new ArgumentNullException(nameof(primaryKeyName)); + + if (poco == null) + throw new ArgumentNullException(nameof(poco)); + + if (columns?.Any() == false) + return Task.FromResult(0); + + return ExecuteUpdateAsync(cancellationToken, tableName, primaryKeyName, poco, primaryKeyValue, columns); + } + + /// + public Task UpdateAsync(CancellationToken cancellationToken, Sql sql) + { + if (sql == null) + throw new ArgumentNullException(nameof(sql)); + + var pd = PocoData.ForType(typeof(T), _defaultMapper); + return ExecuteAsync(cancellationToken, new Sql($"UPDATE {_provider.EscapeTableName(pd.TableInfo.TableName)}").Append(sql)); + } + + /// + public Task UpdateAsync(CancellationToken cancellationToken, string sql, params object[] args) + { + if (string.IsNullOrEmpty(sql)) + throw new ArgumentNullException(nameof(sql)); + + var pd = PocoData.ForType(typeof(T), _defaultMapper); + return ExecuteAsync(cancellationToken, $"UPDATE {_provider.EscapeTableName(pd.TableInfo.TableName)} {sql}", args); } +#endif private void PreExecuteUpdate(string tableName, string primaryKeyName, object poco, object primaryKeyValue, IEnumerable columns, IDbCommand cmd) { @@ -2256,126 +2349,34 @@ private void PreExecuteUpdate(string tableName, string primaryKeyName, object po AddParam(cmd, primaryKeyValue, col); } -#if ASYNC - - /// - public Task UpdateAsync(string tableName, string primaryKeyName, object poco, object primaryKeyValue) - => UpdateAsync(CancellationToken.None, tableName, primaryKeyName, poco, primaryKeyValue); - - /// - public Task UpdateAsync(CancellationToken cancellationToken, string tableName, string primaryKeyName, object poco, object primaryKeyValue) - => UpdateAsync(cancellationToken, tableName, primaryKeyName, poco, primaryKeyValue, null); - - /// - public Task UpdateAsync(string tableName, string primaryKeyName, object poco, object primaryKeyValue, IEnumerable columns) - => UpdateAsync(CancellationToken.None, tableName, primaryKeyName, poco, primaryKeyValue, columns); - - /// - public Task UpdateAsync(CancellationToken cancellationToken, string tableName, string primaryKeyName, object poco, object primaryKeyValue, - IEnumerable columns) - { - if (string.IsNullOrEmpty(tableName)) - throw new ArgumentNullException(nameof(tableName)); - - if (string.IsNullOrEmpty(primaryKeyName)) - throw new ArgumentNullException(nameof(primaryKeyName)); - - if (poco == null) - throw new ArgumentNullException(nameof(poco)); - - if (columns?.Any() == false) - return Task.FromResult(0); - - return ExecuteUpdateAsync(cancellationToken, tableName, primaryKeyName, poco, primaryKeyValue, columns); - } - - /// - public Task UpdateAsync(string tableName, string primaryKeyName, object poco) - => UpdateAsync(CancellationToken.None, tableName, primaryKeyName, poco); - - /// - public Task UpdateAsync(CancellationToken cancellationToken, string tableName, string primaryKeyName, object poco) - => UpdateAsync(cancellationToken, tableName, primaryKeyName, poco, null); - - /// - public Task UpdateAsync(string tableName, string primaryKeyName, object poco, IEnumerable columns) - => UpdateAsync(CancellationToken.None, tableName, primaryKeyName, poco, columns); - - /// - public Task UpdateAsync(CancellationToken cancellationToken, string tableName, string primaryKeyName, object poco, IEnumerable columns) - => UpdateAsync(cancellationToken, tableName, primaryKeyName, poco, null, columns); - - /// - public Task UpdateAsync(object poco, IEnumerable columns) - => UpdateAsync(CancellationToken.None, poco, columns); - - /// - public Task UpdateAsync(CancellationToken cancellationToken, object poco, IEnumerable columns) - => UpdateAsync(cancellationToken, poco, null, columns); - - /// - public Task UpdateAsync(object poco) - => UpdateAsync(CancellationToken.None, poco); - - /// - public Task UpdateAsync(CancellationToken cancellationToken, object poco) - => UpdateAsync(cancellationToken, poco, null, null); - - /// - public Task UpdateAsync(object poco, object primaryKeyValue) - => UpdateAsync(CancellationToken.None, poco, primaryKeyValue); - - /// - public Task UpdateAsync(CancellationToken cancellationToken, object poco, object primaryKeyValue) - => UpdateAsync(cancellationToken, poco, primaryKeyValue, null); - - /// - public Task UpdateAsync(object poco, object primaryKeyValue, IEnumerable columns) - => UpdateAsync(CancellationToken.None, poco, primaryKeyValue, columns); - - /// - public Task UpdateAsync(CancellationToken cancellationToken, object poco, object primaryKeyValue, IEnumerable columns) - { - if (poco == null) - throw new ArgumentNullException(nameof(poco)); - - if (columns?.Any() == false) - return Task.FromResult(0); - - var pd = PocoData.ForType(poco.GetType(), _defaultMapper); - return ExecuteUpdateAsync(cancellationToken, pd.TableInfo.TableName, pd.TableInfo.PrimaryKey, poco, primaryKeyValue, columns); - } - - /// - public Task UpdateAsync(string sql, params object[] args) - => UpdateAsync(CancellationToken.None, sql, args); - - /// - public Task UpdateAsync(CancellationToken cancellationToken, string sql, params object[] args) - { - if (string.IsNullOrEmpty(sql)) - throw new ArgumentNullException(nameof(sql)); - - var pd = PocoData.ForType(typeof(T), _defaultMapper); - return ExecuteAsync(cancellationToken, $"UPDATE {_provider.EscapeTableName(pd.TableInfo.TableName)} {sql}", args); - } - - /// - public Task UpdateAsync(Sql sql) - => UpdateAsync(CancellationToken.None, sql); - - /// - public Task UpdateAsync(CancellationToken cancellationToken, Sql sql) + private int ExecuteUpdate(string tableName, string primaryKeyName, object poco, object primaryKeyValue, IEnumerable columns) { - if (sql == null) - throw new ArgumentNullException(nameof(sql)); - - var pd = PocoData.ForType(typeof(T), _defaultMapper); - return ExecuteAsync(cancellationToken, new Sql($"UPDATE {_provider.EscapeTableName(pd.TableInfo.TableName)}").Append(sql)); + try + { + OpenSharedConnection(); + try + { + using (var cmd = CreateCommand(_sharedConnection, string.Empty)) + { + PreExecuteUpdate(tableName, primaryKeyName, poco, primaryKeyValue, columns, cmd); + return ExecuteNonQueryHelper(cmd); + } + } + finally + { + CloseSharedConnection(); + } + } + catch (Exception x) + { + if (OnException(x)) + throw; + return -1; + } } - private async Task ExecuteUpdateAsync(CancellationToken cancellationToken, string tableName, string primaryKeyName, object poco, - object primaryKeyValue, IEnumerable columns) +#if ASYNC + private async Task ExecuteUpdateAsync(CancellationToken cancellationToken, string tableName, string primaryKeyName, object poco, object primaryKeyValue, IEnumerable columns) { try { @@ -2400,18 +2401,24 @@ private async Task ExecuteUpdateAsync(CancellationToken cancellationToken, return -1; } } - #endif -#endregion + #endregion -#region operation: Delete + #region Delete, DeleteAsync + + /// + public int Delete(object poco) + { + var pd = PocoData.ForType(poco.GetType(), _defaultMapper); + return Delete(pd.TableInfo.TableName, pd.TableInfo.PrimaryKey, poco); + } - /// + /// public int Delete(string tableName, string primaryKeyName, object poco) => Delete(tableName, primaryKeyName, poco, null); - /// + /// public int Delete(string tableName, string primaryKeyName, object poco, object primaryKeyValue) { if (primaryKeyValue == null) @@ -2425,15 +2432,8 @@ public int Delete(string tableName, string primaryKeyName, object poco, object p return Execute(sql, primaryKeyValue); } - /// - public int Delete(object poco) - { - var pd = PocoData.ForType(poco.GetType(), _defaultMapper); - return Delete(pd.TableInfo.TableName, pd.TableInfo.PrimaryKey, poco); - } - - /// - public int Delete(object pocoOrPrimaryKey) + /// + public int Delete(object pocoOrPrimaryKey) { if (pocoOrPrimaryKey.GetType() == typeof(T)) return Delete(pocoOrPrimaryKey); @@ -2453,35 +2453,57 @@ public int Delete(object pocoOrPrimaryKey) return Delete(pd.TableInfo.TableName, pd.TableInfo.PrimaryKey, null, pocoOrPrimaryKey); } - /// - public int Delete(string sql, params object[] args) + /// + public int Delete(Sql sql) { var pd = PocoData.ForType(typeof(T), _defaultMapper); - return Execute($"DELETE FROM {_provider.EscapeTableName(pd.TableInfo.TableName)} {sql}", args); + return Execute(new Sql($"DELETE FROM {_provider.EscapeTableName(pd.TableInfo.TableName)}").Append(sql)); } - /// - public int Delete(Sql sql) + /// + public int Delete(string sql, params object[] args) { var pd = PocoData.ForType(typeof(T), _defaultMapper); - return Execute(new Sql($"DELETE FROM {_provider.EscapeTableName(pd.TableInfo.TableName)}").Append(sql)); + return Execute($"DELETE FROM {_provider.EscapeTableName(pd.TableInfo.TableName)} {sql}", args); } #if ASYNC + /// + public Task DeleteAsync(object poco) + => DeleteAsync(CancellationToken.None, poco); - /// + /// public Task DeleteAsync(string tableName, string primaryKeyName, object poco) => DeleteAsync(CancellationToken.None, tableName, primaryKeyName, poco); - /// - public Task DeleteAsync(CancellationToken cancellationToken, string tableName, string primaryKeyName, object poco) - => DeleteAsync(cancellationToken, tableName, primaryKeyName, poco, null); - - /// + /// public Task DeleteAsync(string tableName, string primaryKeyName, object poco, object primaryKeyValue) => DeleteAsync(CancellationToken.None, tableName, primaryKeyName, poco, primaryKeyValue); - /// + /// + public Task DeleteAsync(object pocoOrPrimaryKey) + => DeleteAsync(CancellationToken.None, pocoOrPrimaryKey); + + /// + public Task DeleteAsync(Sql sql) + => DeleteAsync(CancellationToken.None, sql); + + /// + public Task DeleteAsync(string sql, params object[] args) + => DeleteAsync(CancellationToken.None, sql, args); + + /// + public Task DeleteAsync(CancellationToken cancellationToken, object poco) + { + var pd = PocoData.ForType(poco.GetType(), _defaultMapper); + return DeleteAsync(cancellationToken, pd.TableInfo.TableName, pd.TableInfo.PrimaryKey, poco); + } + + /// + public Task DeleteAsync(CancellationToken cancellationToken, string tableName, string primaryKeyName, object poco) + => DeleteAsync(cancellationToken, tableName, primaryKeyName, poco, null); + + /// public Task DeleteAsync(CancellationToken cancellationToken, string tableName, string primaryKeyName, object poco, object primaryKeyValue) { if (primaryKeyValue == null) @@ -2495,22 +2517,7 @@ public Task DeleteAsync(CancellationToken cancellationToken, string tableNa return ExecuteAsync(cancellationToken, sql, primaryKeyValue); } - /// - public Task DeleteAsync(object poco) - => DeleteAsync(CancellationToken.None, poco); - - /// - public Task DeleteAsync(CancellationToken cancellationToken, object poco) - { - var pd = PocoData.ForType(poco.GetType(), _defaultMapper); - return DeleteAsync(cancellationToken, pd.TableInfo.TableName, pd.TableInfo.PrimaryKey, poco); - } - - /// - public Task DeleteAsync(object pocoOrPrimaryKey) - => DeleteAsync(CancellationToken.None, pocoOrPrimaryKey); - - /// + /// public Task DeleteAsync(CancellationToken cancellationToken, object pocoOrPrimaryKey) { if (pocoOrPrimaryKey.GetType() == typeof(T)) @@ -2531,59 +2538,56 @@ public Task DeleteAsync(CancellationToken cancellationToken, object poco return DeleteAsync(cancellationToken, pd.TableInfo.TableName, pd.TableInfo.PrimaryKey, null, pocoOrPrimaryKey); } - /// - public Task DeleteAsync(string sql, params object[] args) - => DeleteAsync(CancellationToken.None, sql, args); - - /// - public Task DeleteAsync(CancellationToken cancellationToken, string sql, params object[] args) + /// + public Task DeleteAsync(CancellationToken cancellationToken, Sql sql) { var pd = PocoData.ForType(typeof(T), _defaultMapper); - return ExecuteAsync(cancellationToken, $"DELETE FROM {_provider.EscapeTableName(pd.TableInfo.TableName)} {sql}", args); + return ExecuteAsync(cancellationToken, new Sql($"DELETE FROM {_provider.EscapeTableName(pd.TableInfo.TableName)}").Append(sql)); } - /// - public Task DeleteAsync(Sql sql) - => DeleteAsync(CancellationToken.None, sql); - - /// - public Task DeleteAsync(CancellationToken cancellationToken, Sql sql) + /// + public Task DeleteAsync(CancellationToken cancellationToken, string sql, params object[] args) { var pd = PocoData.ForType(typeof(T), _defaultMapper); - return ExecuteAsync(cancellationToken, new Sql($"DELETE FROM {_provider.EscapeTableName(pd.TableInfo.TableName)}").Append(sql)); + return ExecuteAsync(cancellationToken, $"DELETE FROM {_provider.EscapeTableName(pd.TableInfo.TableName)} {sql}", args); } - #endif -#endregion + #endregion -#region operation: IsNew + #region IsNew - /// + /// /// Thrown if is null. - /// Thrown if is null or empty. - public bool IsNew(string primaryKeyName, object poco) + public bool IsNew(object poco) { if (poco == null) throw new ArgumentNullException(nameof(poco)); - if (string.IsNullOrEmpty(primaryKeyName)) - throw new ArgumentException("primaryKeyName"); - - return IsNew(primaryKeyName, PocoData.ForObject(poco, primaryKeyName, _defaultMapper), poco); + var pd = PocoData.ForType(poco.GetType(), _defaultMapper); + return IsNew(pd.TableInfo.PrimaryKey, pd, poco); } - /// + /// /// Thrown if is null. - public bool IsNew(object poco) + /// Thrown if is null or empty. + public bool IsNew(string primaryKeyName, object poco) { if (poco == null) throw new ArgumentNullException(nameof(poco)); - var pd = PocoData.ForType(poco.GetType(), _defaultMapper); - return IsNew(pd.TableInfo.PrimaryKey, pd, poco); + if (string.IsNullOrEmpty(primaryKeyName)) + throw new ArgumentException("primaryKeyName"); + + return IsNew(primaryKeyName, PocoData.ForObject(poco, primaryKeyName, _defaultMapper), poco); } + /// + /// The name of the primary key column. + /// A PocoData object for the object instance. + /// The object instance whose "newness" is to be tested. + /// Thrown when the table represented by the given has no auto-incrementing primary key column. + /// Thrown when the doesn't have a property matching the primary key column name. protected virtual bool IsNew(string primaryKeyName, PocoData pd, object poco) { if (string.IsNullOrEmpty(primaryKeyName) || poco is ExpandoObject) @@ -2634,11 +2638,18 @@ protected virtual bool IsNew(string primaryKeyName, PocoData pd, object poco) return pk == Activator.CreateInstance(pk.GetType()); } -#endregion + #endregion -#region operation: Save + #region Save, SaveAsync - /// + /// + public void Save(object poco) + { + var pd = PocoData.ForType(poco.GetType(), _defaultMapper); + Save(pd.TableInfo.TableName, pd.TableInfo.PrimaryKey, poco); + } + + /// public void Save(string tableName, string primaryKeyName, object poco) { if (IsNew(primaryKeyName, poco)) @@ -2647,20 +2658,23 @@ public void Save(string tableName, string primaryKeyName, object poco) Update(tableName, primaryKeyName, poco); } - /// - public void Save(object poco) - { - var pd = PocoData.ForType(poco.GetType(), _defaultMapper); - Save(pd.TableInfo.TableName, pd.TableInfo.PrimaryKey, poco); - } - #if ASYNC + /// + public Task SaveAsync(object poco) + => SaveAsync(CancellationToken.None, poco); - /// + /// public Task SaveAsync(string tableName, string primaryKeyName, object poco) => SaveAsync(CancellationToken.None, tableName, primaryKeyName, poco); - /// + /// + public Task SaveAsync(CancellationToken cancellationToken, object poco) + { + var pd = PocoData.ForType(poco.GetType(), _defaultMapper); + return SaveAsync(cancellationToken, pd.TableInfo.TableName, pd.TableInfo.PrimaryKey, poco); + } + + /// public Task SaveAsync(CancellationToken cancellationToken, string tableName, string primaryKeyName, object poco) { if (IsNew(primaryKeyName, poco)) @@ -2668,312 +2682,385 @@ public Task SaveAsync(CancellationToken cancellationToken, string tableName, str return UpdateAsync(cancellationToken, tableName, primaryKeyName, poco); } - - /// - public Task SaveAsync(object poco) - => SaveAsync(CancellationToken.None, poco); - - /// - public Task SaveAsync(CancellationToken cancellationToken, object poco) - { - var pd = PocoData.ForType(poco.GetType(), _defaultMapper); - return SaveAsync(cancellationToken, pd.TableInfo.TableName, pd.TableInfo.PrimaryKey, poco); - } - #endif -#endregion + #endregion -#region operation: Multi-Poco Query/Fetch + #region StoredProcedures, StoredProceduresAsync - /// - public List Fetch(Func cb, string sql, params object[] args) - => Query(cb, sql, args).ToList(); + /// + public int ExecuteNonQueryProc(string storedProcedureName, params object[] args) + => ExecuteInternal(CommandType.StoredProcedure, storedProcedureName, args); - /// - public List Fetch(Func cb, string sql, params object[] args) - => Query(cb, sql, args).ToList(); + /// + public T ExecuteScalarProc(string storedProcedureName, params object[] args) + => ExecuteScalarInternal(CommandType.StoredProcedure, storedProcedureName, args); - /// - public List Fetch(Func cb, string sql, params object[] args) - => Query(cb, sql, args).ToList(); + /// + public IEnumerable QueryProc(string storedProcedureName, params object[] args) + => ExecuteReader(CommandType.StoredProcedure, storedProcedureName, args); - /// - public List Fetch(Func cb, string sql, params object[] args) - => Query(cb, sql, args).ToList(); + /// + public List FetchProc(string storedProcedureName, params object[] args) + => QueryProc(storedProcedureName, args).ToList(); - /// - public IEnumerable Query(Func cb, string sql, params object[] args) - => Query(new[] { typeof(T1), typeof(T2) }, cb, sql, args); +#if ASYNC + /// + public Task ExecuteNonQueryProcAsync(string storedProcedureName, params object[] args) + => ExecuteNonQueryProcAsync(CancellationToken.None, storedProcedureName, args); - /// - public IEnumerable Query(Func cb, string sql, params object[] args) - => Query(new[] { typeof(T1), typeof(T2), typeof(T3) }, cb, sql, args); + /// + public Task ExecuteScalarProcAsync(string storedProcedureName, params object[] args) + => ExecuteScalarProcAsync(CancellationToken.None, storedProcedureName, args); - /// - public IEnumerable Query(Func cb, string sql, params object[] args) - => Query(new[] { typeof(T1), typeof(T2), typeof(T3), typeof(T4) }, cb, sql, args); + /// + public Task> QueryProcAsync(string storedProcedureName, params object[] args) + => QueryProcAsync(CancellationToken.None, storedProcedureName, args); - public IEnumerable Query(Func cb, string sql, params object[] args) - => Query(new[] { typeof(T1), typeof(T2), typeof(T3), typeof(T4), typeof(T5) }, cb, sql, args); + /// + public Task QueryProcAsync(Action receivePocoCallback, string storedProcedureName, params object[] args) + => QueryProcAsync(receivePocoCallback, CancellationToken.None, storedProcedureName, args); - /// - public List Fetch(Func cb, Sql sql) - => Query(cb, sql.SQL, sql.Arguments).ToList(); + /// + public Task> FetchProcAsync(string storedProcedureName, params object[] args) + => FetchProcAsync(CancellationToken.None, storedProcedureName, args); - /// - public List Fetch(Func cb, Sql sql) - => Query(cb, sql.SQL, sql.Arguments).ToList(); + /// + public Task ExecuteNonQueryProcAsync(CancellationToken cancellationToken, string storedProcedureName, params object[] args) + => ExecuteInternalAsync(cancellationToken, CommandType.StoredProcedure, storedProcedureName, args); - /// - public List Fetch(Func cb, Sql sql) - => Query(cb, sql.SQL, sql.Arguments).ToList(); + /// + public Task ExecuteScalarProcAsync(CancellationToken cancellationToken, string storedProcedureName, params object[] args) + => ExecuteScalarInternalAsync(cancellationToken, CommandType.StoredProcedure, storedProcedureName, args); - public List Fetch(Func cb, Sql sql) - => Query(cb, sql.SQL, sql.Arguments).ToList(); + /// + public Task> QueryProcAsync(CancellationToken cancellationToken, string storedProcedureName, params object[] args) + => ExecuteReaderAsync(cancellationToken, CommandType.StoredProcedure, storedProcedureName, args); - /// - public IEnumerable Query(Func cb, Sql sql) - => Query(new[] { typeof(T1), typeof(T2) }, cb, sql.SQL, sql.Arguments); + /// + public Task QueryProcAsync(Action receivePocoCallback, CancellationToken cancellationToken, string storedProcedureName, params object[] args) + => ExecuteReaderAsync(receivePocoCallback, cancellationToken, CommandType.StoredProcedure, storedProcedureName, args); - /// - public IEnumerable Query(Func cb, Sql sql) - => Query(new[] { typeof(T1), typeof(T2), typeof(T3) }, cb, sql.SQL, sql.Arguments); + /// + public async Task> FetchProcAsync(CancellationToken cancellationToken, string storedProcedureName, params object[] args) + { + var pocos = new List(); + await ExecuteReaderAsync(p => pocos.Add(p), cancellationToken, CommandType.StoredProcedure, storedProcedureName, args); + return pocos; + } +#endif - /// - public IEnumerable Query(Func cb, Sql sql) - => Query(new[] { typeof(T1), typeof(T2), typeof(T3), typeof(T4) }, cb, sql.SQL, sql.Arguments); + #endregion - /// - public IEnumerable Query(Func cb, Sql sql) - => Query(new[] { typeof(T1), typeof(T2), typeof(T3), typeof(T4), typeof(T5) }, cb, sql.SQL, sql.Arguments); + #region Command & Parameter Creation - /// - public List Fetch(string sql, params object[] args) - => Query(sql, args).ToList(); + public IDbCommand CreateCommand(IDbConnection connection, string sql, params object[] args) + => CreateCommand(connection, CommandType.Text, sql, args); - /// - public List Fetch(string sql, params object[] args) - => Query(sql, args).ToList(); + public IDbCommand CreateCommand(IDbConnection connection, CommandType commandType, string sql, params object[] args) + { + var cmd = connection.CreateCommand(); - /// - public List Fetch(string sql, params object[] args) - => Query(sql, args).ToList(); + try + { + cmd.CommandType = commandType; + cmd.Transaction = _transaction; - /// - public List Fetch(string sql, params object[] args) - => Query(sql, args).ToList(); + switch (commandType) + { + case CommandType.Text: + // Perform named argument replacements + if (EnableNamedParams) + { + var newArgs = new List(); + sql = ParametersHelper.ProcessQueryParams(sql, args, newArgs); + args = newArgs.ToArray(); + } - /// - public IEnumerable Query(string sql, params object[] args) - => Query(new[] { typeof(T1), typeof(T2) }, null, sql, args); + // Perform parameter prefix replacements + if (_paramPrefix != "@") + sql = sql.ReplaceParamPrefix(_paramPrefix); + sql = sql.Replace("@@", "@"); // <- double @@ escapes a single @ + break; + case CommandType.StoredProcedure: + args = ParametersHelper.ProcessStoredProcParams(cmd, args, SetParameterProperties); + break; + case CommandType.TableDirect: + break; + } - /// - public IEnumerable Query(string sql, params object[] args) - => Query(new[] { typeof(T1), typeof(T2), typeof(T3) }, null, sql, args); + cmd.CommandText = sql; - /// - public IEnumerable Query(string sql, params object[] args) - => Query(new[] { typeof(T1), typeof(T2), typeof(T3), typeof(T4) }, null, sql, args); + foreach (var item in args) + AddParam(cmd, item, null); - /// - public IEnumerable Query(string sql, params object[] args) - => Query(new[] { typeof(T1), typeof(T2), typeof(T3), typeof(T4), typeof(T5) }, null, sql, args); + return cmd; + } + catch + { + cmd.Dispose(); + throw; + } + } - /// - public List Fetch(Sql sql) - => Query(sql.SQL, sql.Arguments).ToList(); + /// + /// Creates an IDbDataParameter with default values. + /// + /// The IDbDataParameter. + public IDbDataParameter CreateParameter() + => _factory.CreateParameter(); - /// - public List Fetch(Sql sql) - => Query(sql.SQL, sql.Arguments).ToList(); + /// + /// Creates an IDbDataParameter with the given name and value. + /// + /// The parameter name. + /// The parameter value. + /// The IDbDataParameter. + public IDbDataParameter CreateParameter(string name, object value) + => CreateParameter(name, value, ParameterDirection.Input); - /// - public List Fetch(Sql sql) - => Query(sql.SQL, sql.Arguments).ToList(); + /// + /// Creates an IDbDataParameter with the given name and direction. + /// + /// The parameter name. + /// The parameter direction. + /// The IDbDataParameter. + public IDbDataParameter CreateParameter(string name, ParameterDirection direction) + => CreateParameter(name, null, direction); - /// - public List Fetch(Sql sql) - => Query(sql.SQL, sql.Arguments).ToList(); + /// + /// Create an IDbParameter with the given ParameterName, Value, and Direction. + /// + /// The parameter name. + /// The parameter value. + /// The parameter direction. + /// The IDbDataParameter. + public IDbDataParameter CreateParameter(string name, object value, ParameterDirection direction) + { + var result = CreateParameter(); + result.ParameterName = name; + result.Value = value; + result.Direction = direction; + return result; + } - /// - public IEnumerable Query(Sql sql) - => Query(new[] { typeof(T1), typeof(T2) }, null, sql.SQL, sql.Arguments); + private void SetParameterProperties(IDbDataParameter p, object value, PocoColumn pc) + { + // Assign the parameter value + if (value == null) + { + p.Value = DBNull.Value; - /// - public IEnumerable Query(Sql sql) - => Query(new[] { typeof(T1), typeof(T2), typeof(T3) }, null, sql.SQL, sql.Arguments); + if (pc?.PropertyInfo.PropertyType.Name == "Byte[]") + p.DbType = DbType.Binary; + } + else + { + // Give the database type first crack at converting to DB required type + value = _provider.MapParameterValue(value); - public IEnumerable Query(Sql sql) - => Query(new[] { typeof(T1), typeof(T2), typeof(T3), typeof(T4) }, null, sql.SQL, sql.Arguments); + var t = value.GetType(); - /// - public IEnumerable Query(Sql sql) - => Query(new[] { typeof(T1), typeof(T2), typeof(T3), typeof(T4), typeof(T5) }, null, sql.SQL, sql.Arguments); + if (t == typeof(string) && pc?.ForceToAnsiString == true) + { + t = typeof(AnsiString); + value = value.ToAnsiString(); + } + if (t == typeof(DateTime) && pc?.ForceToDateTime2 == true) + { + t = typeof(DateTime2); + value = ((DateTime)value).ToDateTime2(); + } - /// - public IEnumerable Query(Type[] types, object cb, string sql, params object[] args) - { - OpenSharedConnection(); - try - { - using (var cmd = CreateCommand(_sharedConnection, sql, args)) + if (t.IsEnum) // PostgreSQL .NET driver wont cast enum to int { - IDataReader r; - try + p.Value = Convert.ChangeType(value, ((Enum)value).GetTypeCode()); + } + else if (t == typeof(Guid) && !_provider.HasNativeGuidSupport) + { + p.Value = value.ToString(); + p.DbType = DbType.String; + p.Size = 40; + } + else if (t == typeof(string)) + { + // out of memory exception occurs if trying to save more than 4000 characters to SQL Server CE NText column. Set before attempting to set Size, or Size will always max out at 4000 + if ((value as string).Length + 1 > 4000 && p.GetType().Name == "SqlCeParameter") + p.GetType().GetProperty("SqlDbType").SetValue(p, SqlDbType.NText, null); + + p.Size = Math.Max((value as string).Length + 1, 4000); // Help query plan caching by using common size + p.Value = value; + } + else if (t == typeof(AnsiString)) + { + var asValue = (value as AnsiString).Value; + if (asValue == null) { - r = ExecuteReaderHelper(cmd); + p.Size = 0; + p.Value = DBNull.Value; } - catch (Exception x) + else { - if (OnException(x)) - throw; - yield break; + p.Size = Math.Max(asValue.Length + 1, 4000); + p.Value = asValue; } + // Thanks @DataChomp for pointing out the SQL Server indexing performance hit of using wrong string type on varchar + p.DbType = DbType.AnsiString; + } + else if (t == typeof(DateTime2)) + { + var dt2Value = (value as DateTime2)?.Value; + p.Value = dt2Value ?? (object)DBNull.Value; + p.DbType = DbType.DateTime2; + } + else if (value.GetType().Name == "SqlGeography") //SqlGeography is a CLR Type + { + p.GetType().GetProperty("UdtTypeName").SetValue(p, "geography", null); //geography is the equivalent SQL Server Type + p.Value = value; + } + else if (value.GetType().Name == "SqlGeometry") //SqlGeometry is a CLR Type + { + p.GetType().GetProperty("UdtTypeName").SetValue(p, "geometry", null); //geography is the equivalent SQL Server Type + p.Value = value; + } + else if (t == typeof(byte[])) + { + p.Value = value; + p.DbType = DbType.Binary; + } + else + { + p.Value = value; + } + } + } - var factory = MultiPocoFactory.GetFactory(types, _sharedConnection.ConnectionString, sql, r, _defaultMapper); - if (cb == null) - cb = MultiPocoFactory.GetAutoMapper(types.ToArray()); - var bNeedTerminator = false; - using (r) - { - while (true) - { - TRet poco; - try - { - if (!r.Read()) - break; - poco = factory(r, cb); - } - catch (Exception x) - { - if (OnException(x)) - throw; - yield break; - } + /// + /// Adds a parameter to a DB command. + /// + /// A reference to the IDbCommand to which the parameter is to be added. + /// The value to assign to the parameter. + /// Optional, a reference to the property info of the POCO property from which the value is coming. + private void AddParam(IDbCommand cmd, object value, PocoColumn pc) + { + // Convert value to from poco type to db type + if (pc != null) + { + var mapper = Mappers.GetMapper(pc.PropertyInfo.DeclaringType, _defaultMapper); + var fn = mapper.GetToDbConverter(pc.PropertyInfo); + if (fn != null) + value = fn(value); + } - if (poco != null) - yield return poco; - else - bNeedTerminator = true; - } + // Support passed in parameters + if (value is IDbDataParameter idbParam) + { + if (cmd.CommandType == CommandType.Text) + idbParam.ParameterName = cmd.Parameters.Count.EnsureParamPrefix(_paramPrefix); + else if (idbParam.ParameterName?.StartsWith(_paramPrefix) != true) + idbParam.ParameterName = idbParam.ParameterName.EnsureParamPrefix(_paramPrefix); - if (bNeedTerminator) - { - var poco = (TRet) (cb as Delegate).DynamicInvoke(new object[types.Length]); - if (poco != null) - yield return poco; - else - yield break; - } - } - } + cmd.Parameters.Add(idbParam); } - finally + else { - CloseSharedConnection(); + var p = cmd.CreateParameter(); + p.ParameterName = cmd.Parameters.Count.EnsureParamPrefix(_paramPrefix); + SetParameterProperties(p, value, pc); + + cmd.Parameters.Add(p); } } -#endregion + #endregion -#region operation: Multi-Result Set + #region Execute Command Helpers - public IGridReader QueryMultiple(Sql sql) - => QueryMultiple(sql.SQL, sql.Arguments); + internal protected IDataReader ExecuteReaderHelper(IDbCommand cmd) + { + return (IDataReader)CommandHelper(cmd, c => c.ExecuteReader()); + } - public IGridReader QueryMultiple(string sql, params object[] args) + internal protected int ExecuteNonQueryHelper(IDbCommand cmd) { - OpenSharedConnection(); + return (int)CommandHelper(cmd, c => c.ExecuteNonQuery()); + } - GridReader result = null; + internal protected object ExecuteScalarHelper(IDbCommand cmd) + { + return CommandHelper(cmd, c => c.ExecuteScalar()); + } - var cmd = CreateCommand(_sharedConnection, sql, args); + private object CommandHelper(IDbCommand cmd, Func cmdFunc) + { + DoPreExecute(cmd); + var result = cmdFunc(cmd); + OnExecutedCommand(cmd); + return result; + } - try +#if ASYNC + internal protected async Task ExecuteReaderHelperAsync(CancellationToken cancellationToken, IDbCommand cmd) + { + if (cmd is DbCommand dbCommand) { - var reader = ExecuteReaderHelper(cmd); - result = new GridReader(this, cmd, reader, _defaultMapper); + var task = CommandHelper(cancellationToken, dbCommand, + async (t, c) => await c.ExecuteReaderAsync(t).ConfigureAwait(false)); + return (IDataReader)await task.ConfigureAwait(false); } - catch (Exception x) + else + return ExecuteReaderHelper(cmd); + } + + internal protected async Task ExecuteNonQueryHelperAsync(CancellationToken cancellationToken, IDbCommand cmd) + { + if (cmd is DbCommand dbCommand) { - if (OnException(x)) - throw; + var task = CommandHelper(cancellationToken, dbCommand, + async (t, c) => await c.ExecuteNonQueryAsync(t).ConfigureAwait(false)); + return (int)await task.ConfigureAwait(false); } - - return result; + else + return ExecuteNonQueryHelper(cmd); } -#endregion - -#region operation: StoredProc - - /// - public IEnumerable QueryProc(string storedProcedureName, params object[] args) - => ExecuteReader(CommandType.StoredProcedure, storedProcedureName, args); - - /// - public List FetchProc(string storedProcedureName, params object[] args) - => QueryProc(storedProcedureName, args).ToList(); - - /// - public T ExecuteScalarProc(string storedProcedureName, params object[] args) - => ExecuteScalarInternal(CommandType.StoredProcedure, storedProcedureName, args); - - /// - public int ExecuteNonQueryProc(string storedProcedureName, params object[] args) - => ExecuteInternal(CommandType.StoredProcedure, storedProcedureName, args); - -#if ASYNC - /// - public Task QueryProcAsync(Action receivePocoCallback, string storedProcedureName, params object[] args) - => QueryProcAsync(receivePocoCallback, CancellationToken.None, storedProcedureName, args); - - /// - public Task QueryProcAsync(Action receivePocoCallback, CancellationToken cancellationToken, string storedProcedureName, params object[] args) - => ExecuteReaderAsync(receivePocoCallback, cancellationToken, CommandType.StoredProcedure, storedProcedureName, args); - - /// - public Task> QueryProcAsync(string storedProcedureName, params object[] args) - => QueryProcAsync(CancellationToken.None, storedProcedureName, args); - - /// - public Task> QueryProcAsync(CancellationToken cancellationToken, string storedProcedureName, params object[] args) - => ExecuteReaderAsync(cancellationToken, CommandType.StoredProcedure, storedProcedureName, args); - - /// - public Task> FetchProcAsync(string storedProcedureName, params object[] args) - => FetchProcAsync(CancellationToken.None, storedProcedureName, args); - - /// - public async Task> FetchProcAsync(CancellationToken cancellationToken, string storedProcedureName, params object[] args) + internal protected Task ExecuteScalarHelperAsync(CancellationToken cancellationToken, IDbCommand cmd) { - var pocos = new List(); - await ExecuteReaderAsync(p => pocos.Add(p), cancellationToken, CommandType.StoredProcedure, storedProcedureName, args); - return pocos; + if (cmd is DbCommand dbCommand) + return CommandHelper(cancellationToken, dbCommand, + async (t, c) => await c.ExecuteScalarAsync(cancellationToken).ConfigureAwait(false)); + else + return Task.FromResult(ExecuteScalarHelper(cmd)); } - /// - public Task ExecuteScalarProcAsync(string storedProcedureName, params object[] args) - => ExecuteScalarProcAsync(CancellationToken.None, storedProcedureName, args); + private async Task CommandHelper(CancellationToken cancellationToken, DbCommand cmd, + Func> cmdFunc) + { + DoPreExecute(cmd); + var result = await cmdFunc(cancellationToken, cmd).ConfigureAwait(false); + OnExecutedCommand(cmd); + return result; + } +#endif - /// - public Task ExecuteScalarProcAsync(CancellationToken cancellationToken, string storedProcedureName, params object[] args) - => ExecuteScalarInternalAsync(cancellationToken, CommandType.StoredProcedure, storedProcedureName, args); + #endregion - /// - public Task ExecuteNonQueryProcAsync(string storedProcedureName, params object[] args) - => ExecuteNonQueryProcAsync(CancellationToken.None, storedProcedureName, args); + internal void DoPreExecute(IDbCommand cmd) + { + if (CommandTimeout > 0 || OneTimeCommandTimeout > 0) + { + cmd.CommandTimeout = OneTimeCommandTimeout > 0 ? OneTimeCommandTimeout : CommandTimeout; + OneTimeCommandTimeout = 0; + } - /// - public Task ExecuteNonQueryProcAsync(CancellationToken cancellationToken, string storedProcedureName, params object[] args) - => ExecuteInternalAsync(cancellationToken, CommandType.StoredProcedure, storedProcedureName, args); -#endif + _provider.PreExecute(cmd); + OnExecutingCommand(cmd); -#endregion + _lastSql = cmd.CommandText; + _lastArgs = cmd.Parameters.Cast().Select(parameter => parameter.Value).ToArray(); + } -#region Last Command + #region Last Command, Format Command /// /// Gets the SQL used for the most recently executed statement. @@ -2990,10 +3077,6 @@ public Task ExecuteNonQueryProcAsync(CancellationToken cancellationToken, s /// public string LastCommand => FormatCommand(_lastSql, _lastArgs); -#endregion - -#region FormatCommand - /// /// Formats the contents of a DB command for display. /// @@ -3030,9 +3113,9 @@ public string FormatCommand(string sql, object[] args) return sb.ToString(); } -#endregion + #endregion -#region Public Properties + #region Configuration Properties /// /// Gets the default mapper. @@ -3040,35 +3123,15 @@ public string FormatCommand(string sql, object[] args) public IMapper DefaultMapper => _defaultMapper; /// - /// When set to , PetaPoco will automatically create the "SELECT columns" part of any query that looks like it needs it. - /// - public bool EnableAutoSelect { get; set; } - - /// - /// When set to , parameters can be named ?myparam and populated from properties of the passed-in argument values. - /// - public bool EnableNamedParams { get; set; } - - /// - /// Gets or sets the timeout value for all SQL statements. - /// - public int CommandTimeout { get; set; } - - /// - /// Gets or sets the timeout value for the next (and only next) SQL statement. + /// Gets the connection string. /// - public int OneTimeCommandTimeout { get; set; } + public string ConnectionString => _connectionString; /// /// Gets the loaded database provider. /// public IProvider Provider => _provider; - /// - /// Gets the connection string. - /// - public string ConnectionString => _connectionString; - /// /// Gets or sets the transaction isolation level. /// @@ -3085,79 +3148,35 @@ public IsolationLevel? IsolationLevel } } -#endregion - -#region Helpers - internal protected IDataReader ExecuteReaderHelper(IDbCommand cmd) - { - return (IDataReader)CommandHelper(cmd, c => c.ExecuteReader()); - } - - internal protected int ExecuteNonQueryHelper(IDbCommand cmd) - { - return (int)CommandHelper(cmd, c => c.ExecuteNonQuery()); - } - - internal protected object ExecuteScalarHelper(IDbCommand cmd) - { - return CommandHelper(cmd, c => c.ExecuteScalar()); - } - - private object CommandHelper(IDbCommand cmd, Func cmdFunc) - { - DoPreExecute(cmd); - var result = cmdFunc(cmd); - OnExecutedCommand(cmd); - return result; - } + /// + /// When set to the first opened connection is kept alive until or is called. + /// + /// + public bool KeepConnectionAlive { get; set; } -#if ASYNC - internal protected async Task ExecuteReaderHelperAsync(CancellationToken cancellationToken, IDbCommand cmd) - { - if (cmd is DbCommand dbCommand) - { - var task = CommandHelper(cancellationToken, dbCommand, - async (t, c) => await c.ExecuteReaderAsync(t).ConfigureAwait(false)); - return (IDataReader)await task.ConfigureAwait(false); - } - else - return ExecuteReaderHelper(cmd); - } + /// + /// When set to , PetaPoco will automatically create the "SELECT columns" part of any query that looks like it needs it. + /// + public bool EnableAutoSelect { get; set; } - internal protected async Task ExecuteNonQueryHelperAsync(CancellationToken cancellationToken, IDbCommand cmd) - { - if (cmd is DbCommand dbCommand) - { - var task = CommandHelper(cancellationToken, dbCommand, - async (t, c) => await c.ExecuteNonQueryAsync(t).ConfigureAwait(false)); - return (int)await task.ConfigureAwait(false); - } - else - return ExecuteNonQueryHelper(cmd); - } + /// + /// When set to , parameters can be named ?myparam and populated from properties of the passed-in argument values. + /// + public bool EnableNamedParams { get; set; } - internal protected Task ExecuteScalarHelperAsync(CancellationToken cancellationToken, IDbCommand cmd) - { - if (cmd is DbCommand dbCommand) - return CommandHelper(cancellationToken, dbCommand, - async (t, c) => await c.ExecuteScalarAsync(cancellationToken).ConfigureAwait(false)); - else - return Task.FromResult(ExecuteScalarHelper(cmd)); - } + /// + /// Gets or sets the timeout value for all SQL statements. + /// + public int CommandTimeout { get; set; } - private async Task CommandHelper(CancellationToken cancellationToken, DbCommand cmd, - Func> cmdFunc) - { - DoPreExecute(cmd); - var result = await cmdFunc(cancellationToken, cmd).ConfigureAwait(false); - OnExecutedCommand(cmd); - return result; - } -#endif + /// + /// Gets or sets the timeout value for the next (and only next) SQL statement. + /// + public int OneTimeCommandTimeout { get; set; } -#endregion + #endregion -#region Events + #region Events /// public event EventHandler TransactionStarted; @@ -3172,18 +3191,18 @@ private async Task CommandHelper(CancellationToken cancellationToken, Db public event EventHandler CommandExecuted; /// - public event EventHandler ConnectionClosing; + public event EventHandler ConnectionOpening; /// public event EventHandler ConnectionOpened; /// - public event EventHandler ConnectionOpening; + public event EventHandler ConnectionClosing; /// public event EventHandler ExceptionThrown; -#endregion + #endregion } /// diff --git a/PetaPoco/DatabaseConfigurationExtensions.cs b/PetaPoco/DatabaseConfigurationExtensions.cs index 85d40bfe..5fa286ea 100644 --- a/PetaPoco/DatabaseConfigurationExtensions.cs +++ b/PetaPoco/DatabaseConfigurationExtensions.cs @@ -12,13 +12,13 @@ public static class DatabaseConfigurationExtensions internal const string CommandTimeout = "CommandTimeout"; internal const string EnableAutoSelect = "EnableAutoSelect"; internal const string EnableNamedParams = "EnableNamedParams"; - internal const string Provider = "Provider"; - internal const string ConnectionString = "ConnectionString"; - internal const string ProviderName = "ProviderName"; #if !NETSTANDARD internal const string ConnectionStringName = "ConnectionStringName"; #endif + internal const string ConnectionString = "ConnectionString"; + internal const string ProviderName = "ProviderName"; + internal const string Provider = "Provider"; internal const string DefaultMapper = "DefaultMapper"; internal const string IsolationLevel = "IsolationLevel"; @@ -37,6 +37,8 @@ private static void SetSetting(this IDatabaseBuildConfiguration source, string k ((IBuildConfigurationSettings) source).SetSetting(key, value); } + #region Timeout Settings + /// /// Adds a command timeout - see . /// @@ -52,208 +54,223 @@ public static IDatabaseBuildConfiguration UsingCommandTimeout(this IDatabaseBuil return source; } + #endregion + + #region AutoSelect Settings + /// - /// Enables named params - see . + /// Enables auto select . /// /// The configuration source. /// The original configuration, to form a fluent interface. - public static IDatabaseBuildConfiguration WithNamedParams(this IDatabaseBuildConfiguration source) + public static IDatabaseBuildConfiguration WithAutoSelect(this IDatabaseBuildConfiguration source) { - source.SetSetting(EnableNamedParams, true); + source.SetSetting(EnableAutoSelect, true); return source; } /// - /// Disables named params - see . + /// Disables auto select - see . /// /// The configuration source. /// The original configuration, to form a fluent interface. - public static IDatabaseBuildConfiguration WithoutNamedParams(this IDatabaseBuildConfiguration source) + public static IDatabaseBuildConfiguration WithoutAutoSelect(this IDatabaseBuildConfiguration source) { - source.SetSetting(EnableNamedParams, false); + source.SetSetting(EnableAutoSelect, false); return source; } + #endregion + + #region NamedParams Settings + /// - /// Specifies the provider to be used. - see . This takes precedence over . + /// Enables named params - see . /// /// The configuration source. - /// The provider to use. /// The original configuration, to form a fluent interface. - /// Thrown when is null. - public static IDatabaseBuildConfiguration UsingProvider(this IDatabaseBuildConfiguration source, T provider) where T : class, IProvider + public static IDatabaseBuildConfiguration WithNamedParams(this IDatabaseBuildConfiguration source) { - if (provider == null) - throw new ArgumentNullException(nameof(provider)); - source.SetSetting(Provider, provider); + source.SetSetting(EnableNamedParams, true); return source; } /// - /// Specifies the provider to be used. - see . This takes precedence over . + /// Disables named params - see . /// - /// The provider type. /// The configuration source. - /// The configure provider callback. - /// The provider to use. /// The original configuration, to form a fluent interface. - /// Thrown when is null. - /// Thrown when is null. - public static IDatabaseBuildConfiguration UsingProvider(this IDatabaseBuildConfiguration source, T provider, Action configure) where T : class, IProvider + public static IDatabaseBuildConfiguration WithoutNamedParams(this IDatabaseBuildConfiguration source) { - if (provider == null) - throw new ArgumentNullException(nameof(provider)); - if (configure == null) - throw new ArgumentNullException(nameof(configure)); - configure(provider); - source.SetSetting(Provider, provider); + source.SetSetting(EnableNamedParams, false); return source; } + #endregion + + #region Connection Settings + +#if !NETSTANDARD /// - /// Specifies the provider to be used. - see . This takes precedence over . + /// Adds a connection string name. /// - /// The provider type. /// The configuration source. + /// The connection string name. /// The original configuration, to form a fluent interface. - public static IDatabaseBuildConfiguration UsingProvider(this IDatabaseBuildConfiguration source) where T : class, IProvider, new() + /// Thrown when is null or empty. + public static IDatabaseBuildConfiguration UsingConnectionStringName(this IDatabaseBuildConfiguration source, string connectionStringName) { - source.SetSetting(Provider, new T()); + if (string.IsNullOrEmpty(connectionStringName)) + throw new ArgumentException("Argument is null or empty", nameof(connectionStringName)); + source.SetSetting(ConnectionStringName, connectionStringName); return source; } +#endif /// - /// Specifies the to use, with an accompanying configuration provider custom callback. + /// Adds a connection string - see . /// - /// The provider type, constrained to a class deriving from . /// The configuration source. - /// The configure provider callback. + /// The connection string. /// The original configuration, to form a fluent interface. - /// Thrown when is null. - public static IDatabaseBuildConfiguration UsingProvider(this IDatabaseBuildConfiguration source, Action configure) where T : class, IProvider, new() + /// Thrown when is null or empty. + public static IDatabaseBuildConfiguration UsingConnectionString(this IDatabaseBuildConfiguration source, string connectionString) { - if (configure == null) - throw new ArgumentNullException(nameof(configure)); - var provider = new T(); - configure(provider); - source.SetSetting(Provider, provider); + if (string.IsNullOrEmpty(connectionString)) + throw new ArgumentException("Argument is null or empty", nameof(connectionString)); + source.SetSetting(ConnectionString, connectionString); return source; } /// - /// Enables auto select . + /// Specifies an to use. /// /// The configuration source. + /// The connection to use. /// The original configuration, to form a fluent interface. - public static IDatabaseBuildConfiguration WithAutoSelect(this IDatabaseBuildConfiguration source) + public static IDatabaseBuildConfiguration UsingConnection(this IDatabaseBuildConfiguration source, IDbConnection connection) { - source.SetSetting(EnableAutoSelect, true); + if (connection == null) + throw new ArgumentNullException(nameof(connection)); + + source.SetSetting(Connection, connection); return source; } + #endregion + + #region Provider Settings + /// - /// Disables auto select - see . + /// Adds a provider name string - see . /// /// The configuration source. + /// The provider name. /// The original configuration, to form a fluent interface. - public static IDatabaseBuildConfiguration WithoutAutoSelect(this IDatabaseBuildConfiguration source) + /// Thrown when is null or empty. + public static IDatabaseBuildConfiguration UsingProviderName(this IDatabaseBuildConfiguration source, string providerName) { - source.SetSetting(EnableAutoSelect, false); + if (string.IsNullOrEmpty(providerName)) + throw new ArgumentException("Argument is null or empty", nameof(providerName)); + source.SetSetting(ProviderName, providerName); return source; } /// - /// Adds a connection string - see . + /// Specifies the provider to be used. - see . This takes precedence over . /// + /// The provider type. /// The configuration source. - /// The connection string. /// The original configuration, to form a fluent interface. - /// Thrown when is null or empty. - public static IDatabaseBuildConfiguration UsingConnectionString(this IDatabaseBuildConfiguration source, string connectionString) + public static IDatabaseBuildConfiguration UsingProvider(this IDatabaseBuildConfiguration source) where T : class, IProvider, new() { - if (string.IsNullOrEmpty(connectionString)) - throw new ArgumentException("Argument is null or empty", nameof(connectionString)); - source.SetSetting(ConnectionString, connectionString); + source.SetSetting(Provider, new T()); return source; } -#if !NETSTANDARD /// - /// Adds a connection string name. + /// Specifies the to use, with an accompanying configuration provider custom callback. /// + /// The provider type, constrained to a class deriving from . /// The configuration source. - /// The connection string name. + /// The configure provider callback. /// The original configuration, to form a fluent interface. - /// Thrown when is null or empty. - public static IDatabaseBuildConfiguration UsingConnectionStringName(this IDatabaseBuildConfiguration source, string connectionStringName) + /// Thrown when is null. + public static IDatabaseBuildConfiguration UsingProvider(this IDatabaseBuildConfiguration source, Action configure) where T : class, IProvider, new() { - if (string.IsNullOrEmpty(connectionStringName)) - throw new ArgumentException("Argument is null or empty", nameof(connectionStringName)); - source.SetSetting(ConnectionStringName, connectionStringName); + if (configure == null) + throw new ArgumentNullException(nameof(configure)); + var provider = new T(); + configure(provider); + source.SetSetting(Provider, provider); return source; } -#endif /// - /// Adds a provider name string - see . + /// Specifies the provider to be used. - see . This takes precedence over . /// /// The configuration source. - /// The provider name. + /// The provider to use. /// The original configuration, to form a fluent interface. - /// Thrown when is null or empty. - public static IDatabaseBuildConfiguration UsingProviderName(this IDatabaseBuildConfiguration source, string providerName) + /// Thrown when is null. + public static IDatabaseBuildConfiguration UsingProvider(this IDatabaseBuildConfiguration source, T provider) where T : class, IProvider { - if (string.IsNullOrEmpty(providerName)) - throw new ArgumentException("Argument is null or empty", nameof(providerName)); - source.SetSetting(ProviderName, providerName); + if (provider == null) + throw new ArgumentNullException(nameof(provider)); + source.SetSetting(Provider, provider); return source; } /// - /// Specifies an to use. + /// Specifies the provider to be used. - see . This takes precedence over . /// + /// The provider type. /// The configuration source. - /// The connection to use. + /// The configure provider callback. + /// The provider to use. /// The original configuration, to form a fluent interface. - public static IDatabaseBuildConfiguration UsingConnection(this IDatabaseBuildConfiguration source, IDbConnection connection) + /// Thrown when is null. + /// Thrown when is null. + public static IDatabaseBuildConfiguration UsingProvider(this IDatabaseBuildConfiguration source, T provider, Action configure) where T : class, IProvider { - if (connection == null) - throw new ArgumentNullException(nameof(connection)); - - source.SetSetting(Connection, connection); + if (provider == null) + throw new ArgumentNullException(nameof(provider)); + if (configure == null) + throw new ArgumentNullException(nameof(configure)); + configure(provider); + source.SetSetting(Provider, provider); return source; } + #endregion + + #region Mapper Settings + /// /// Specifies the default mapper to use when no specific mapper has been registered. /// + /// The mapper type. /// The configuration source. - /// The mapper to use as the default. /// The original configuration, to form a fluent interface. - /// Thrown when is null. - public static IDatabaseBuildConfiguration UsingDefaultMapper(this IDatabaseBuildConfiguration source, T mapper) where T : class, IMapper + public static IDatabaseBuildConfiguration UsingDefaultMapper(this IDatabaseBuildConfiguration source) where T : class, IMapper, new() { - if (mapper == null) - throw new ArgumentNullException(nameof(mapper)); - source.SetSetting(DefaultMapper, mapper); + source.SetSetting(DefaultMapper, new T()); return source; } /// /// Specifies the default mapper to use when no specific mapper has been registered. /// + /// The type of the mapper. This type must be a class that implements the interface. /// The configuration source. - /// The mapper to use as the default. - /// The configure mapper callback. + /// A callback function to configure the mapper. /// The original configuration, to form a fluent interface. - /// Thrown when is null. - /// Thrown when is null. - public static IDatabaseBuildConfiguration UsingDefaultMapper(this IDatabaseBuildConfiguration source, T mapper, Action configure) where T : class, IMapper + /// Thrown if the callback function is null. + public static IDatabaseBuildConfiguration UsingDefaultMapper(this IDatabaseBuildConfiguration source, Action configure) where T : class, IMapper, new() { - if (mapper == null) - throw new ArgumentNullException(nameof(mapper)); if (configure == null) throw new ArgumentNullException(nameof(configure)); + var mapper = new T(); configure(mapper); source.SetSetting(DefaultMapper, mapper); return source; @@ -262,33 +279,42 @@ public static IDatabaseBuildConfiguration UsingDefaultMapper(this IDatabaseBu /// /// Specifies the default mapper to use when no specific mapper has been registered. /// - /// The mapper type. /// The configuration source. + /// The mapper to use as the default. /// The original configuration, to form a fluent interface. - public static IDatabaseBuildConfiguration UsingDefaultMapper(this IDatabaseBuildConfiguration source) where T : class, IMapper, new() + /// Thrown when is null. + public static IDatabaseBuildConfiguration UsingDefaultMapper(this IDatabaseBuildConfiguration source, T mapper) where T : class, IMapper { - source.SetSetting(DefaultMapper, new T()); + if (mapper == null) + throw new ArgumentNullException(nameof(mapper)); + source.SetSetting(DefaultMapper, mapper); return source; } /// /// Specifies the default mapper to use when no specific mapper has been registered. /// - /// The type of the mapper. This type must be a class that implements the interface. /// The configuration source. - /// A callback function to configure the mapper. + /// The mapper to use as the default. + /// The configure mapper callback. /// The original configuration, to form a fluent interface. - /// Thrown if the callback function is null. - public static IDatabaseBuildConfiguration UsingDefaultMapper(this IDatabaseBuildConfiguration source, Action configure) where T : class, IMapper, new() + /// Thrown when is null. + /// Thrown when is null. + public static IDatabaseBuildConfiguration UsingDefaultMapper(this IDatabaseBuildConfiguration source, T mapper, Action configure) where T : class, IMapper { + if (mapper == null) + throw new ArgumentNullException(nameof(mapper)); if (configure == null) throw new ArgumentNullException(nameof(configure)); - var mapper = new T(); configure(mapper); source.SetSetting(DefaultMapper, mapper); return source; } + #endregion + + #region Transaction Settings + /// /// Specifies the transaction isolation level to use. /// @@ -301,6 +327,10 @@ public static IDatabaseBuildConfiguration UsingIsolationLevel(this IDatabaseBuil return source; } + #endregion + + #region Event Settings + /// /// Specifies an event handler to use when a new transaction has been started. /// @@ -397,6 +427,10 @@ public static IDatabaseBuildConfiguration UsingExceptionThrown(this IDatabaseBui return source; } + #endregion + + #region Finalize Fluent Configuration + /// /// Creates an instance of PetaPoco using the specified . /// @@ -406,5 +440,7 @@ public static IDatabase Create(this IDatabaseBuildConfiguration source) { return new Database(source); } + + #endregion } } diff --git a/PetaPoco/IAlterPoco.cs b/PetaPoco/IAlterPoco.cs index cbdaa0b4..30240182 100644 --- a/PetaPoco/IAlterPoco.cs +++ b/PetaPoco/IAlterPoco.cs @@ -6,6 +6,16 @@ public interface IAlterPoco { #region Insert + /// + /// Performs an SQL Insert. + /// + /// + /// The name of the table, its primary key and whether it's an auto-allocated primary key are retrieved from the POCO's attributes + /// + /// A POCO object containing the column values to be inserted. + /// The auto allocated primary key of the new record, or for non-auto-increment tables. + object Insert(object poco); + /// /// Performs an SQL Insert. /// @@ -36,16 +46,6 @@ public interface IAlterPoco /// The auto allocated primary key of the new record, or for non-auto-increment tables. object Insert(string tableName, string primaryKeyName, bool autoIncrement, object poco); - /// - /// Performs an SQL Insert. - /// - /// - /// The name of the table, its primary key and whether it's an auto-allocated primary key are retrieved from the POCO's attributes - /// - /// A POCO object containing the column values to be inserted. - /// The auto allocated primary key of the new record, or for non-auto-increment tables. - object Insert(object poco); - #endregion #region Update @@ -53,96 +53,103 @@ public interface IAlterPoco /// /// Performs an SQL update. /// - /// The name of the table to update. - /// The name of the primary key column of the table. /// A POCO object containing the column values to be updated. - /// The primary key of the record to be updated. - /// The number of affected records. - int Update(string tableName, string primaryKeyName, object poco, object primaryKeyValue); + /// The number of affected rows. + int Update(object poco); /// /// Performs an SQL update. /// - /// The name of the table to update. - /// The name of the primary key column of the table. /// A POCO object containing the column values to be updated. - /// The primary key of the record to be updated. /// The column names of the columns to be updated, or for all. /// The number of affected rows. - int Update(string tableName, string primaryKeyName, object poco, object primaryKeyValue, IEnumerable columns); + int Update(object poco, IEnumerable columns); /// /// Performs an SQL update. /// - /// The name of the table to update. - /// The name of the primary key column of the table. /// A POCO object containing the column values to be updated. + /// The primary key of the record to be updated. /// The number of affected rows. - int Update(string tableName, string primaryKeyName, object poco); + int Update(object poco, object primaryKeyValue); /// /// Performs an SQL update. /// - /// The name of the table to update. - /// The name of the primary key column of the table. /// A POCO object containing the column values to be updated. + /// The primary key of the record to be updated. /// The column names of the columns to be updated, or for all. /// The number of affected rows. - int Update(string tableName, string primaryKeyName, object poco, IEnumerable columns); + int Update(object poco, object primaryKeyValue, IEnumerable columns); /// /// Performs an SQL update. /// + /// The name of the table to update. + /// The name of the primary key column of the table. /// A POCO object containing the column values to be updated. - /// The column names of the columns to be updated, or for all. /// The number of affected rows. - int Update(object poco, IEnumerable columns); + int Update(string tableName, string primaryKeyName, object poco); /// /// Performs an SQL update. /// + /// The name of the table to update. + /// The name of the primary key column of the table. /// A POCO object containing the column values to be updated. + /// The column names of the columns to be updated, or for all. /// The number of affected rows. - int Update(object poco); + int Update(string tableName, string primaryKeyName, object poco, IEnumerable columns); /// /// Performs an SQL update. /// + /// The name of the table to update. + /// The name of the primary key column of the table. /// A POCO object containing the column values to be updated. /// The primary key of the record to be updated. - /// The number of affected rows. - int Update(object poco, object primaryKeyValue); + /// The number of affected records. + int Update(string tableName, string primaryKeyName, object poco, object primaryKeyValue); /// /// Performs an SQL update. /// + /// The name of the table to update. + /// The name of the primary key column of the table. /// A POCO object containing the column values to be updated. /// The primary key of the record to be updated. /// The column names of the columns to be updated, or for all. /// The number of affected rows. - int Update(object poco, object primaryKeyValue, IEnumerable columns); + int Update(string tableName, string primaryKeyName, object poco, object primaryKeyValue, IEnumerable columns); /// /// Performs an SQL update. /// /// The POCO class whose attributes specify the name of the table to update. - /// The SQL update and condition clause (everything after UPDATE tablename). - /// Arguments to any embedded parameters in the SQL. + /// An SQL builder object representing the SQL update and condition clause (everything after UPDATE tablename). /// The number of affected rows. - int Update(string sql, params object[] args); + int Update(Sql sql); /// /// Performs an SQL update. /// /// The POCO class whose attributes specify the name of the table to update. - /// An SQL builder object representing the SQL update and condition clause (everything after UPDATE tablename). + /// The SQL update and condition clause (everything after UPDATE tablename). + /// Arguments to any embedded parameters in the SQL. /// The number of affected rows. - int Update(Sql sql); + int Update(string sql, params object[] args); #endregion #region Delete + /// + /// Performs an SQL Delete. + /// + /// A POCO object specifying the table name and primary key value of the row to be deleted. + /// The number of rows affected. + int Delete(object poco); + /// /// Performs an SQL Delete. /// @@ -162,13 +169,6 @@ public interface IAlterPoco /// The number of rows affected. int Delete(string tableName, string primaryKeyName, object poco, object primaryKeyValue); - /// - /// Performs an SQL Delete. - /// - /// A POCO object specifying the table name and primary key value of the row to be deleted. - /// The number of rows affected. - int Delete(object poco); - /// /// Performs an SQL Delete. /// @@ -181,18 +181,18 @@ public interface IAlterPoco /// Performs an SQL Delete. /// /// The POCO class whose attributes specify the name of the table to delete from. - /// The SQL condition clause identifying the row to delete (everything after DELETE FROM tablename). - /// Arguments to any embedded parameters in the SQL. + /// An SQL builder object representing the SQL condition clause identifying the row to delete (everything after DELETE FROM tablename). /// The number of affected rows. - int Delete(string sql, params object[] args); + int Delete(Sql sql); /// /// Performs an SQL Delete. /// /// The POCO class whose attributes specify the name of the table to delete from. - /// An SQL builder object representing the SQL condition clause identifying the row to delete (everything after DELETE FROM tablename). + /// The SQL condition clause identifying the row to delete (everything after DELETE FROM tablename). + /// Arguments to any embedded parameters in the SQL. /// The number of affected rows. - int Delete(Sql sql); + int Delete(string sql, params object[] args); #endregion @@ -204,10 +204,9 @@ public interface IAlterPoco /// /// This method simply tests if the POCO's primary key column property has a non-default value. /// - /// The name of the primary key column. /// The object instance whose "newness" is to be tested. /// if the POCO represents a record already in the database. - bool IsNew(string primaryKeyName, object poco); + bool IsNew(object poco); /// /// Checks if a poco represents a new row. @@ -215,9 +214,10 @@ public interface IAlterPoco /// /// This method simply tests if the POCO's primary key column property has a non-default value. /// + /// The name of the primary key column. /// The object instance whose "newness" is to be tested. /// if the POCO represents a record already in the database. - bool IsNew(object poco); + bool IsNew(string primaryKeyName, object poco); #endregion @@ -226,16 +226,16 @@ public interface IAlterPoco /// /// Saves a POCO by performing either an INSERT or UPDATE operation. /// - /// The name of the table to be updated. - /// The name of the primary key column. /// The POCO object to be saved. - void Save(string tableName, string primaryKeyName, object poco); + void Save(object poco); /// /// Saves a POCO by performing either an INSERT or UPDATE operation. /// + /// The name of the table to be updated. + /// The name of the primary key column. /// The POCO object to be saved. - void Save(object poco); + void Save(string tableName, string primaryKeyName, object poco); #endregion } diff --git a/PetaPoco/IAlterPocoAsync.cs b/PetaPoco/IAlterPocoAsync.cs index d0cd4918..16ccb2ad 100644 --- a/PetaPoco/IAlterPocoAsync.cs +++ b/PetaPoco/IAlterPocoAsync.cs @@ -7,17 +7,17 @@ namespace PetaPoco #if ASYNC public interface IAlterPocoAsync { - #region Insert + #region InsertAsync /// - /// Async version of . + /// Async version of . /// - Task InsertAsync(string tableName, object poco); + Task InsertAsync(object poco); /// /// Async version of . /// - Task InsertAsync(CancellationToken cancellationToken, string tableName, object poco); + Task InsertAsync(string tableName, object poco); /// /// Async version of . @@ -25,88 +25,83 @@ public interface IAlterPocoAsync Task InsertAsync(string tableName, string primaryKeyName, object poco); /// - /// Async version of . + /// Async version of . /// - Task InsertAsync(CancellationToken cancellationToken, string tableName, string primaryKeyName, object poco); + Task InsertAsync(string tableName, string primaryKeyName, bool autoIncrement, object poco); /// - /// Async version of . + /// Async version of . /// - Task InsertAsync(string tableName, string primaryKeyName, bool autoIncrement, object poco); + Task InsertAsync(CancellationToken cancellationToken, object poco); /// - /// Async version of . + /// Async version of . /// - Task InsertAsync(CancellationToken cancellationToken, string tableName, string primaryKeyName, bool autoIncrement, object poco); + Task InsertAsync(CancellationToken cancellationToken, string tableName, object poco); /// - /// Async version of . + /// Async version of . /// - Task InsertAsync(object poco); + Task InsertAsync(CancellationToken cancellationToken, string tableName, string primaryKeyName, object poco); /// - /// Async version of . + /// Async version of . /// - Task InsertAsync(CancellationToken cancellationToken, object poco); + Task InsertAsync(CancellationToken cancellationToken, string tableName, string primaryKeyName, bool autoIncrement, object poco); #endregion - #region Update + #region UpdateAsync /// - /// Async version of . + /// Async version of . /// - Task UpdateAsync(string tableName, string primaryKeyName, object poco, object primaryKeyValue); + Task UpdateAsync(object poco); /// - /// Async version of . + /// Async version of . /// - Task UpdateAsync(CancellationToken cancellationToken, string tableName, string primaryKeyName, object poco, object primaryKeyValue); + Task UpdateAsync(object poco, IEnumerable columns); /// - /// Async version of . + /// Async version of . /// - Task UpdateAsync(string tableName, string primaryKeyName, object poco, object primaryKeyValue, IEnumerable columns); + Task UpdateAsync(object poco, object primaryKeyValue); /// - /// Async version of . + /// Async version of . /// - Task UpdateAsync(CancellationToken cancellationToken, string tableName, string primaryKeyName, object poco, object primaryKeyValue, IEnumerable columns); + Task UpdateAsync(object poco, object primaryKeyValue, IEnumerable columns); /// /// Async version of . /// Task UpdateAsync(string tableName, string primaryKeyName, object poco); - /// - /// Async version of . - /// - Task UpdateAsync(CancellationToken cancellationToken, string tableName, string primaryKeyName, object poco); - /// /// Async version of . /// Task UpdateAsync(string tableName, string primaryKeyName, object poco, IEnumerable columns); /// - /// Async version of . + /// Async version of . /// - Task UpdateAsync(CancellationToken cancellationToken, string tableName, string primaryKeyName, object poco, IEnumerable columns); + Task UpdateAsync(string tableName, string primaryKeyName, object poco, object primaryKeyValue); /// - /// Async version of . + /// Async version of . /// - Task UpdateAsync(object poco, IEnumerable columns); + Task UpdateAsync(string tableName, string primaryKeyName, object poco, object primaryKeyValue, IEnumerable columns); /// - /// Async version of . + /// Async version of . /// - Task UpdateAsync(CancellationToken cancellationToken, object poco, IEnumerable columns); + Task UpdateAsync(Sql sql); /// - /// Async version of . + /// Async version of . /// - Task UpdateAsync(object poco); + Task UpdateAsync(string sql, params object[] args); /// /// Async version of . @@ -114,9 +109,9 @@ public interface IAlterPocoAsync Task UpdateAsync(CancellationToken cancellationToken, object poco); /// - /// Async version of . + /// Async version of . /// - Task UpdateAsync(object poco, object primaryKeyValue); + Task UpdateAsync(CancellationToken cancellationToken, object poco, IEnumerable columns); /// /// Async version of . @@ -126,46 +121,51 @@ public interface IAlterPocoAsync /// /// Async version of . /// - Task UpdateAsync(object poco, object primaryKeyValue, IEnumerable columns); + Task UpdateAsync(CancellationToken cancellationToken, object poco, object primaryKeyValue, IEnumerable columns); /// - /// Async version of . + /// Async version of . /// - Task UpdateAsync(CancellationToken cancellationToken, object poco, object primaryKeyValue, IEnumerable columns); + Task UpdateAsync(CancellationToken cancellationToken, string tableName, string primaryKeyName, object poco); /// - /// Async version of . + /// Async version of . /// - Task UpdateAsync(string sql, params object[] args); + Task UpdateAsync(CancellationToken cancellationToken, string tableName, string primaryKeyName, object poco, IEnumerable columns); /// - /// Async version of . + /// Async version of . /// - Task UpdateAsync(CancellationToken cancellationToken, string sql, params object[] args); + Task UpdateAsync(CancellationToken cancellationToken, string tableName, string primaryKeyName, object poco, object primaryKeyValue); /// - /// Async version of . + /// Async version of . /// - Task UpdateAsync(Sql sql); + Task UpdateAsync(CancellationToken cancellationToken, string tableName, string primaryKeyName, object poco, object primaryKeyValue, IEnumerable columns); /// /// Async version of . /// Task UpdateAsync(CancellationToken cancellationToken, Sql sql); + /// + /// Async version of . + /// + Task UpdateAsync(CancellationToken cancellationToken, string sql, params object[] args); + #endregion - #region Delete + #region DeleteAsync /// - /// Async version of . + /// Async version of . /// - Task DeleteAsync(string tableName, string primaryKeyName, object poco); + Task DeleteAsync(object poco); /// /// Async version of . /// - Task DeleteAsync(CancellationToken cancellationToken, string tableName, string primaryKeyName, object poco); + Task DeleteAsync(string tableName, string primaryKeyName, object poco); /// /// Async version of . @@ -173,73 +173,73 @@ public interface IAlterPocoAsync Task DeleteAsync(string tableName, string primaryKeyName, object poco, object primaryKeyValue); /// - /// Async version of . + /// Async version of . /// - Task DeleteAsync(CancellationToken cancellationToken, string tableName, string primaryKeyName, object poco, object primaryKeyValue); + Task DeleteAsync(object pocoOrPrimaryKey); /// - /// Async version of . + /// Async version of . /// - Task DeleteAsync(object poco); + Task DeleteAsync(Sql sql); /// - /// Async version of . + /// Async version of . /// - Task DeleteAsync(CancellationToken cancellationToken, object poco); + Task DeleteAsync(string sql, params object[] args); /// - /// Async version of . + /// Async version of . /// - Task DeleteAsync(object pocoOrPrimaryKey); + Task DeleteAsync(CancellationToken cancellationToken, object poco); /// - /// Async version of . + /// Async version of . /// - Task DeleteAsync(CancellationToken cancellationToken, object pocoOrPrimaryKey); + Task DeleteAsync(CancellationToken cancellationToken, string tableName, string primaryKeyName, object poco); /// - /// Async version of . + /// Async version of . /// - Task DeleteAsync(string sql, params object[] args); + Task DeleteAsync(CancellationToken cancellationToken, string tableName, string primaryKeyName, object poco, object primaryKeyValue); /// - /// Async version of . + /// Async version of . /// - Task DeleteAsync(CancellationToken cancellationToken, string sql, params object[] args); + Task DeleteAsync(CancellationToken cancellationToken, object pocoOrPrimaryKey); /// /// Async version of . /// - Task DeleteAsync(Sql sql); + Task DeleteAsync(CancellationToken cancellationToken, Sql sql); /// - /// Async version of . + /// Async version of . /// - Task DeleteAsync(CancellationToken cancellationToken, Sql sql); + Task DeleteAsync(CancellationToken cancellationToken, string sql, params object[] args); #endregion - #region Save + #region SaveAsync /// - /// Async version of . + /// Async version of . /// - Task SaveAsync(string tableName, string primaryKeyName, object poco); + Task SaveAsync(object poco); /// /// Async version of . /// - Task SaveAsync(CancellationToken cancellationToken, string tableName, string primaryKeyName, object poco); + Task SaveAsync(string tableName, string primaryKeyName, object poco); /// /// Async version of . /// - Task SaveAsync(object poco); + Task SaveAsync(CancellationToken cancellationToken, object poco); /// - /// Async version of . + /// Async version of . /// - Task SaveAsync(CancellationToken cancellationToken, object poco); + Task SaveAsync(CancellationToken cancellationToken, string tableName, string primaryKeyName, object poco); #endregion } diff --git a/PetaPoco/IDatabase.cs b/PetaPoco/IDatabase.cs index 01f8cb96..5d04de0b 100644 --- a/PetaPoco/IDatabase.cs +++ b/PetaPoco/IDatabase.cs @@ -139,6 +139,18 @@ public interface IDatabase : IDisposable, IQuery, IAlterPoco, IExecute, ITransac /// void BeginTransaction(); +#if ASYNC + /// + /// Async version of . + /// + Task BeginTransactionAsync(); + + /// + /// Async version of . + /// + Task BeginTransactionAsync(CancellationToken cancellationToken); +#endif + /// /// Aborts the entire outermost transaction scope. /// @@ -177,31 +189,19 @@ public interface IDatabase : IDisposable, IQuery, IAlterPoco, IExecute, ITransac /// event EventHandler CommandExecuted; - /// - /// Occurs when a database connection is about to be closed. - /// - event EventHandler ConnectionClosing; - /// /// Occurs when a database connection has been opened. /// event EventHandler ConnectionOpened; /// - /// Occurs when a database exception has been thrown. - /// - event EventHandler ExceptionThrown; - -#if ASYNC - /// - /// Async version of . + /// Occurs when a database connection is about to be closed. /// - Task BeginTransactionAsync(); + event EventHandler ConnectionClosing; /// - /// Async version of . + /// Occurs when a database exception has been thrown. /// - Task BeginTransactionAsync(CancellationToken cancellationToken); -#endif + event EventHandler ExceptionThrown; } } diff --git a/PetaPoco/IExecute.cs b/PetaPoco/IExecute.cs index 17e3657b..9fe2154b 100644 --- a/PetaPoco/IExecute.cs +++ b/PetaPoco/IExecute.cs @@ -11,33 +11,33 @@ public interface IExecute /// /// Executes a non-query command. /// - /// The SQL statement to execute. - /// Arguments to any embedded parameters in the SQL statement. + /// An Sql builder object representing the SQL statement and its arguments. /// The number of rows affected. - int Execute(string sql, params object[] args); + int Execute(Sql sql); /// /// Executes a non-query command. /// - /// An Sql builder object representing the SQL statement and its arguments. + /// The SQL statement to execute. + /// Arguments to any embedded parameters in the SQL statement. /// The number of rows affected. - int Execute(Sql sql); + int Execute(string sql, params object[] args); /// /// Executes the query and returns the first column of the first row in the result set. /// /// The type that the result value should be cast to. - /// The SQL query to execute. - /// Arguments to any embedded parameters in the SQL statement. + /// An Sql builder object representing the SQL query and its arguments. /// The scalar value cast to . - T ExecuteScalar(string sql, params object[] args); + T ExecuteScalar(Sql sql); /// /// Executes the query and returns the first column of the first row in the result set. /// /// The type that the result value should be cast to. - /// An Sql builder object representing the SQL query and its arguments. + /// The SQL query to execute. + /// Arguments to any embedded parameters in the SQL statement. /// The scalar value cast to . - T ExecuteScalar(Sql sql); + T ExecuteScalar(string sql, params object[] args); } } diff --git a/PetaPoco/IExecuteAsync.cs b/PetaPoco/IExecuteAsync.cs index b82629e5..38e00178 100644 --- a/PetaPoco/IExecuteAsync.cs +++ b/PetaPoco/IExecuteAsync.cs @@ -12,53 +12,53 @@ namespace PetaPoco /// public interface IExecuteAsync { + /// + Task ExecuteAsync(Sql sql); + /// Task ExecuteAsync(string sql, params object[] args); + /// + Task ExecuteScalarAsync(Sql sql); + + /// + Task ExecuteScalarAsync(string sql, params object[] args); + /// /// Asynchronously executes a non-query command with a cancellation token. /// /// A cancellation token that can be used to cancel the operation. - /// The SQL statement to execute. - /// Arguments to any embedded parameters in the SQL statement. + /// An Sql builder object representing the SQL statement and its arguments. /// A task that represents the asynchronous operation. The task result is the number of rows affected. - Task ExecuteAsync(CancellationToken cancellationToken, string sql, params object[] args); - - /// - Task ExecuteAsync(Sql sql); + Task ExecuteAsync(CancellationToken cancellationToken, Sql sql); /// /// Asynchronously executes a non-query command with a cancellation token. /// /// A cancellation token that can be used to cancel the operation. - /// An Sql builder object representing the SQL statement and its arguments. + /// The SQL statement to execute. + /// Arguments to any embedded parameters in the SQL statement. /// A task that represents the asynchronous operation. The task result is the number of rows affected. - Task ExecuteAsync(CancellationToken cancellationToken, Sql sql); - - /// - Task ExecuteScalarAsync(string sql, params object[] args); + Task ExecuteAsync(CancellationToken cancellationToken, string sql, params object[] args); /// /// Asynchronously executes the query with a cancellation token and returns the first column of the first row in the result set. /// /// The type that the result value should be cast to. /// A cancellation token that can be used to cancel the operation. - /// The SQL query to execute. - /// Arguments to any embedded parameters in the SQL statement. + /// An Sql builder object representing the SQL query and its arguments. /// A task that represents the asynchronous operation. The task result is the scalar value cast to . - Task ExecuteScalarAsync(CancellationToken cancellationToken, string sql, params object[] args); - - /// - Task ExecuteScalarAsync(Sql sql); + Task ExecuteScalarAsync(CancellationToken cancellationToken, Sql sql); /// /// Asynchronously executes the query with a cancellation token and returns the first column of the first row in the result set. /// /// The type that the result value should be cast to. /// A cancellation token that can be used to cancel the operation. - /// An Sql builder object representing the SQL query and its arguments. + /// The SQL query to execute. + /// Arguments to any embedded parameters in the SQL statement. /// A task that represents the asynchronous operation. The task result is the scalar value cast to . - Task ExecuteScalarAsync(CancellationToken cancellationToken, Sql sql); + Task ExecuteScalarAsync(CancellationToken cancellationToken, string sql, params object[] args); } #endif } diff --git a/PetaPoco/IQuery.cs b/PetaPoco/IQuery.cs index 5829f74b..d2bd1a98 100644 --- a/PetaPoco/IQuery.cs +++ b/PetaPoco/IQuery.cs @@ -5,7 +5,7 @@ namespace PetaPoco { public interface IQuery { - #region Query + #region Query : Single-Poco /// /// Streams the result of a select all query (SELECT *). @@ -24,10 +24,9 @@ public interface IQuery /// For some DB providers, care should be taken to not start a new Query before finishing with and disposing of the previous one. In cases where this is an issue, consider using Fetch, which returns the results as a List rather than an IEnumerable. /// /// The Type representing a row in the result set. - /// The SQL query. - /// Arguments to any embedded parameters in the SQL statement. + /// An SQL builder object representing the base SQL query and its arguments. /// An IEnumerable collection of POCOs. - IEnumerable Query(string sql, params object[] args); + IEnumerable Query(Sql sql); /// /// Runs an SQL query, returning the results as an IEnumerable collection. @@ -36,21 +35,66 @@ public interface IQuery /// For some DB providers, care should be taken to not start a new Query before finishing with and disposing of the previous one. In cases where this is an issue, consider using Fetch, which returns the results as a List rather than an IEnumerable. /// /// The Type representing a row in the result set. - /// An SQL builder object representing the base SQL query and its arguments. + /// The SQL query. + /// Arguments to any embedded parameters in the SQL statement. /// An IEnumerable collection of POCOs. - IEnumerable Query(Sql sql); + IEnumerable Query(string sql, params object[] args); + + #endregion + + #region Query : Multi-Poco + + /// + /// Perform a multi-poco query. + /// + /// The first POCO type. + /// The second POCO type. + /// An SQL builder object representing the query and its arguments. + /// A collection of POCOs as an IEnumerable. + IEnumerable Query(Sql sql); + + /// + /// Perform a multi-poco query. + /// + /// The first POCO type. + /// The second POCO type. + /// The third POCO type. + /// An SQL builder object representing the query and its arguments. + /// A collection of POCOs as an IEnumerable. + IEnumerable Query(Sql sql); + + /// + /// Perform a multi-poco query. + /// + /// The first POCO type. + /// The second POCO type. + /// The third POCO type. + /// The fourth POCO type. + /// An SQL builder object representing the query and its arguments. + /// A collection of POCOs as an IEnumerable. + IEnumerable Query(Sql sql); + + /// + /// Perform a multi-poco query. + /// + /// The first POCO type. + /// The second POCO type. + /// The third POCO type. + /// The fourth POCO type. + /// The fifth POCO type. + /// An SQL builder object representing the query and its arguments. + /// A collection of POCOs as an IEnumerable. + IEnumerable Query(Sql sql); /// /// Perform a multi-poco query. /// /// The first POCO type. /// The second POCO type. - /// The type of objects in the returned IEnumerable. - /// A callback function to connect the POCO instances, or to automatically guess the relationships. /// The SQL query to be executed. /// Arguments to any embedded parameters in the SQL. /// A collection of POCOs as an IEnumerable. - IEnumerable Query(Func cb, string sql, params object[] args); + IEnumerable Query(string sql, params object[] args); /// /// Perform a multi-poco query. @@ -58,12 +102,10 @@ public interface IQuery /// The first POCO type. /// The second POCO type. /// The third POCO type. - /// The type of objects in the returned IEnumerable. - /// A callback function to connect the POCO instances, or to automatically guess the relationships. /// The SQL query to be executed. /// Arguments to any embedded parameters in the SQL. /// A collection of POCOs as an IEnumerable. - IEnumerable Query(Func cb, string sql, params object[] args); + IEnumerable Query(string sql, params object[] args); /// /// Perform a multi-poco query. @@ -72,12 +114,10 @@ public interface IQuery /// The second POCO type. /// The third POCO type. /// The fourth POCO type. - /// The type of objects in the returned IEnumerable. - /// A callback function to connect the POCO instances, or to automatically guess the relationships. /// The SQL query to be executed. /// Arguments to any embedded parameters in the SQL. /// A collection of POCOs as an IEnumerable. - IEnumerable Query(Func cb, string sql, params object[] args); + IEnumerable Query(string sql, params object[] args); /// /// Perform a multi-poco query. @@ -87,12 +127,10 @@ public interface IQuery /// The third POCO type. /// The fourth POCO type. /// The fifth POCO type. - /// The type of objects in the returned IEnumerable. - /// A callback function to connect the POCO instances, or to automatically guess the relationships. /// The SQL query to be executed. /// Arguments to any embedded parameters in the SQL. /// A collection of POCOs as an IEnumerable. - IEnumerable Query(Func cb, string sql, params object[] args); + IEnumerable Query(string sql, params object[] args); /// /// Perform a multi-poco query. @@ -149,10 +187,12 @@ public interface IQuery /// /// The first POCO type. /// The second POCO type. + /// The type of objects in the returned IEnumerable. + /// A callback function to connect the POCO instances, or to automatically guess the relationships. /// The SQL query to be executed. /// Arguments to any embedded parameters in the SQL. /// A collection of POCOs as an IEnumerable. - IEnumerable Query(string sql, params object[] args); + IEnumerable Query(Func cb, string sql, params object[] args); /// /// Perform a multi-poco query. @@ -160,10 +200,12 @@ public interface IQuery /// The first POCO type. /// The second POCO type. /// The third POCO type. + /// The type of objects in the returned IEnumerable. + /// A callback function to connect the POCO instances, or to automatically guess the relationships. /// The SQL query to be executed. /// Arguments to any embedded parameters in the SQL. /// A collection of POCOs as an IEnumerable. - IEnumerable Query(string sql, params object[] args); + IEnumerable Query(Func cb, string sql, params object[] args); /// /// Perform a multi-poco query. @@ -172,10 +214,12 @@ public interface IQuery /// The second POCO type. /// The third POCO type. /// The fourth POCO type. + /// The type of objects in the returned IEnumerable. + /// A callback function to connect the POCO instances, or to automatically guess the relationships. /// The SQL query to be executed. /// Arguments to any embedded parameters in the SQL. /// A collection of POCOs as an IEnumerable. - IEnumerable Query(string sql, params object[] args); + IEnumerable Query(Func cb, string sql, params object[] args); /// /// Perform a multi-poco query. @@ -185,67 +229,46 @@ public interface IQuery /// The third POCO type. /// The fourth POCO type. /// The fifth POCO type. + /// The type of objects in the returned IEnumerable. + /// A callback function to connect the POCO instances, or to automatically guess the relationships. /// The SQL query to be executed. /// Arguments to any embedded parameters in the SQL. /// A collection of POCOs as an IEnumerable. - IEnumerable Query(string sql, params object[] args); + IEnumerable Query(Func cb, string sql, params object[] args); /// - /// Perform a multi-poco query. + /// Performs a multi-poco query. /// - /// The first POCO type. - /// The second POCO type. - /// An SQL builder object representing the query and its arguments. + /// The type of objects in the returned IEnumerable. + /// An array of Types representing the POCO types of the returned result set. + /// A callback function to connect the POCO instances, or to automatically guess the relationships. + /// The SQL query to be executed. + /// Arguments to any embedded parameters in the SQL. /// A collection of POCOs as an IEnumerable. - IEnumerable Query(Sql sql); + IEnumerable Query(Type[] types, object cb, string sql, params object[] args); - /// - /// Perform a multi-poco query. - /// - /// The first POCO type. - /// The second POCO type. - /// The third POCO type. - /// An SQL builder object representing the query and its arguments. - /// A collection of POCOs as an IEnumerable. - IEnumerable Query(Sql sql); + #endregion - /// - /// Perform a multi-poco query. - /// - /// The first POCO type. - /// The second POCO type. - /// The third POCO type. - /// The fourth POCO type. - /// An SQL builder object representing the query and its arguments. - /// A collection of POCOs as an IEnumerable. - IEnumerable Query(Sql sql); + #region QueryMultiple : Multi-POCO Result Set IGridReader /// - /// Perform a multi-poco query. + /// Perform a multi-results set query. /// - /// The first POCO type. - /// The second POCO type. - /// The third POCO type. - /// The fourth POCO type. - /// The fifth POCO type. /// An SQL builder object representing the query and its arguments. - /// A collection of POCOs as an IEnumerable. - IEnumerable Query(Sql sql); + /// A GridReader to be queried. + IGridReader QueryMultiple(Sql sql); /// - /// Performs a multi-poco query. + /// Perform a multi-results set query. /// - /// The type of objects in the returned IEnumerable. - /// An array of Types representing the POCO types of the returned result set. - /// A callback function to connect the POCO instances, or to automatically guess the relationships. /// The SQL query to be executed. /// Arguments to any embedded parameters in the SQL. - /// A collection of POCOs as an IEnumerable. - IEnumerable Query(Type[] types, object cb, string sql, params object[] args); + /// A GridReader to be queried. + IGridReader QueryMultiple(string sql, params object[] args); #endregion - #region Fetch + #region Fetch : Single-Poco /// /// Runs a SELECT * query and returns the result set as a typed list. @@ -254,6 +277,14 @@ public interface IQuery /// A List holding the results of the query. List Fetch(); + /// + /// Runs a query and returns the result set as a typed list. + /// + /// The Type representing a row in the result set. + /// An SQL builder object representing the query and its arguments. + /// A List holding the results of the query. + List Fetch(Sql sql); + /// /// Runs a query and returns the result set as a typed list. /// @@ -263,64 +294,61 @@ public interface IQuery /// A List holding the results of the query. List Fetch(string sql, params object[] args); + #endregion + + #region Fetch : Multi-Poco + /// - /// Runs a query and returns the result set as a typed list. + /// Perform a multi-poco fetch. /// - /// The Type representing a row in the result set. + /// The first POCO type. + /// The second POCO type. /// An SQL builder object representing the query and its arguments. - /// A List holding the results of the query. - List Fetch(Sql sql); + /// A collection of POCOs as a List. + List Fetch(Sql sql); /// - /// Retrieves a page of records (without the total count). + /// Perform a multi-poco fetch. /// - /// - /// PetaPoco will automatically modify a default SELECT * statement to only retrieve the records for the specified page. - /// - /// The Type representing a row in the result set. - /// The 1-based page number to retrieve. - /// The number of records per page. - /// A List of results. - List Fetch(long page, long itemsPerPage); + /// The first POCO type. + /// The second POCO type. + /// The third POCO type. + /// An SQL builder object representing the query and its arguments. + /// A collection of POCOs as a List. + List Fetch(Sql sql); /// - /// Retrieves a page of records (without the total count). + /// Perform a multi-poco fetch. /// - /// - /// PetaPoco will automatically modify the supplied SELECT statement to only retrieve the records for the specified page. - /// - /// The Type representing a row in the result set. - /// The 1-based page number to retrieve. - /// The number of records per page. - /// The base SQL query. - /// Arguments to any embedded parameters in the SQL statement. - /// A List of results. - List Fetch(long page, long itemsPerPage, string sql, params object[] args); + /// The first POCO type. + /// The second POCO type. + /// The third POCO type. + /// The fourth POCO type. + /// An SQL builder object representing the query and its arguments. + /// A collection of POCOs as a List. + List Fetch(Sql sql); /// - /// Retrieves a page of records (without the total count). + /// Perform a multi-poco fetch. /// - /// - /// PetaPoco will automatically modify the supplied SELECT statement to only retrieve the records for the specified page. - /// - /// The Type representing a row in the result set. - /// The 1-based page number to retrieve. - /// The number of records per page. - /// An SQL builder object representing the base SQL query and its arguments. - /// A List of results. - List Fetch(long page, long itemsPerPage, Sql sql); + /// The first POCO type. + /// The second POCO type. + /// The third POCO type. + /// The fourth POCO type. + /// The fourth POCO type. + /// An SQL builder object representing the query and its arguments. + /// A collection of POCOs as a List. + List Fetch(Sql sql); /// /// Perform a multi-poco fetch. /// /// The first POCO type. /// The second POCO type. - /// The returned list POCO type. - /// A callback function to connect the POCO instances, or to automatically guess the relationships. /// The SQL query to be executed. /// Arguments to any embedded parameters in the SQL. /// A collection of POCOs as a List. - List Fetch(Func cb, string sql, params object[] args); + List Fetch(string sql, params object[] args); /// /// Perform a multi-poco fetch. @@ -328,12 +356,10 @@ public interface IQuery /// The first POCO type. /// The second POCO type. /// The third POCO type. - /// The returned list POCO type. - /// A callback function to connect the POCO instances, or to automatically guess the relationships. /// The SQL query to be executed. /// Arguments to any embedded parameters in the SQL. /// A collection of POCOs as a List. - List Fetch(Func cb, string sql, params object[] args); + List Fetch(string sql, params object[] args); /// /// Perform a multi-poco fetch. @@ -342,12 +368,10 @@ public interface IQuery /// The second POCO type. /// The third POCO type. /// The fourth POCO type. - /// The returned list POCO type. - /// A callback function to connect the POCO instances, or to automatically guess the relationships. /// The SQL query to be executed. /// Arguments to any embedded parameters in the SQL. /// A collection of POCOs as a List. - List Fetch(Func cb, string sql, params object[] args); + List Fetch(string sql, params object[] args); /// /// Perform a multi-poco fetch. @@ -357,12 +381,10 @@ public interface IQuery /// The third POCO type. /// The fourth POCO type. /// The fifth POCO type. - /// The returned list POCO type. - /// A callback function to connect the POCO instances, or to automatically guess the relationships. /// The SQL query to be executed. /// Arguments to any embedded parameters in the SQL. /// A collection of POCOs as a List. - List Fetch(Func cb, string sql, params object[] args); + List Fetch(string sql, params object[] args); /// /// Perform a multi-poco fetch. @@ -419,10 +441,12 @@ public interface IQuery /// /// The first POCO type. /// The second POCO type. + /// The returned list POCO type. + /// A callback function to connect the POCO instances, or to automatically guess the relationships. /// The SQL query to be executed. /// Arguments to any embedded parameters in the SQL. /// A collection of POCOs as a List. - List Fetch(string sql, params object[] args); + List Fetch(Func cb, string sql, params object[] args); /// /// Perform a multi-poco fetch. @@ -430,10 +454,12 @@ public interface IQuery /// The first POCO type. /// The second POCO type. /// The third POCO type. + /// The returned list POCO type. + /// A callback function to connect the POCO instances, or to automatically guess the relationships. /// The SQL query to be executed. /// Arguments to any embedded parameters in the SQL. /// A collection of POCOs as a List. - List Fetch(string sql, params object[] args); + List Fetch(Func cb, string sql, params object[] args); /// /// Perform a multi-poco fetch. @@ -442,10 +468,12 @@ public interface IQuery /// The second POCO type. /// The third POCO type. /// The fourth POCO type. + /// The returned list POCO type. + /// A callback function to connect the POCO instances, or to automatically guess the relationships. /// The SQL query to be executed. /// Arguments to any embedded parameters in the SQL. /// A collection of POCOs as a List. - List Fetch(string sql, params object[] args); + List Fetch(Func cb, string sql, params object[] args); /// /// Perform a multi-poco fetch. @@ -455,52 +483,55 @@ public interface IQuery /// The third POCO type. /// The fourth POCO type. /// The fifth POCO type. + /// The returned list POCO type. + /// A callback function to connect the POCO instances, or to automatically guess the relationships. /// The SQL query to be executed. /// Arguments to any embedded parameters in the SQL. /// A collection of POCOs as a List. - List Fetch(string sql, params object[] args); + List Fetch(Func cb, string sql, params object[] args); - /// - /// Perform a multi-poco fetch. - /// - /// The first POCO type. - /// The second POCO type. - /// An SQL builder object representing the query and its arguments. - /// A collection of POCOs as a List. - List Fetch(Sql sql); + #endregion + + #region Fetch : Paged SkipTake /// - /// Perform a multi-poco fetch. + /// Retrieves a page of records (without the total count). /// - /// The first POCO type. - /// The second POCO type. - /// The third POCO type. - /// An SQL builder object representing the query and its arguments. - /// A collection of POCOs as a List. - List Fetch(Sql sql); + /// + /// PetaPoco will automatically modify a default SELECT * statement to only retrieve the records for the specified page. + /// + /// The Type representing a row in the result set. + /// The 1-based page number to retrieve. + /// The number of records per page. + /// A List of results. + List Fetch(long page, long itemsPerPage); /// - /// Perform a multi-poco fetch. + /// Retrieves a page of records (without the total count). /// - /// The first POCO type. - /// The second POCO type. - /// The third POCO type. - /// The fourth POCO type. - /// An SQL builder object representing the query and its arguments. - /// A collection of POCOs as a List. - List Fetch(Sql sql); + /// + /// PetaPoco will automatically modify the supplied SELECT statement to only retrieve the records for the specified page. + /// + /// The Type representing a row in the result set. + /// The 1-based page number to retrieve. + /// The number of records per page. + /// An SQL builder object representing the base SQL query and its arguments. + /// A List of results. + List Fetch(long page, long itemsPerPage, Sql sql); /// - /// Perform a multi-poco fetch. + /// Retrieves a page of records (without the total count). /// - /// The first POCO type. - /// The second POCO type. - /// The third POCO type. - /// The fourth POCO type. - /// The fourth POCO type. - /// An SQL builder object representing the query and its arguments. - /// A collection of POCOs as a List. - List Fetch(Sql sql); + /// + /// PetaPoco will automatically modify the supplied SELECT statement to only retrieve the records for the specified page. + /// + /// The Type representing a row in the result set. + /// The 1-based page number to retrieve. + /// The number of records per page. + /// The base SQL query. + /// Arguments to any embedded parameters in the SQL statement. + /// A List of results. + List Fetch(long page, long itemsPerPage, string sql, params object[] args); #endregion @@ -510,29 +541,26 @@ public interface IQuery /// Retrieves a page of records and the total number of available records. /// /// - /// This method allows separate SQL statements to be explicitly provided for the two parts of the page query. The page and itemsPerPage parameters are not used directly and are used simply to populate the returned Page object. + /// PetaPoco will automatically modify a default SELECT * statement to only retrieve the records for the specified page. It will also execute a second query to retrieve the total number of records in the result set. /// /// The Type representing a row in the result set. /// The 1-based page number to retrieve. /// The number of records per page. - /// The SQL to retrieve the total number of records. - /// Arguments to any embedded parameters in the sqlCount statement. - /// The SQL to retrieve a single page of results. - /// Arguments to any embedded parameters in the sqlPage statement. /// A Page of results. - Page Page(long page, long itemsPerPage, string sqlCount, object[] countArgs, string sqlPage, object[] pageArgs); + Page Page(long page, long itemsPerPage); /// /// Retrieves a page of records and the total number of available records. /// /// - /// PetaPoco will automatically modify a default SELECT * statement to only retrieve the records for the specified page. It will also execute a second query to retrieve the total number of records in the result set. + /// PetaPoco will automatically modify the supplied SELECT statement to only retrieve the records for the specified page. It will also execute a second query to retrieve the total number of records in the result set. /// /// The Type representing a row in the result set. /// The 1-based page number to retrieve. /// The number of records per page. + /// An SQL builder object representing the base SQL query and its arguments. /// A Page of results. - Page Page(long page, long itemsPerPage); + Page Page(long page, long itemsPerPage, Sql sql); /// /// Retrieves a page of records and the total number of available records. @@ -552,14 +580,15 @@ public interface IQuery /// Retrieves a page of records and the total number of available records. /// /// - /// PetaPoco will automatically modify the supplied SELECT statement to only retrieve the records for the specified page. It will also execute a second query to retrieve the total number of records in the result set. + /// This method allows separate SQL statements to be explicitly provided for the two parts of the page query. The page and itemsPerPage parameters are not used directly and are used simply to populate the returned Page object. /// /// The Type representing a row in the result set. /// The 1-based page number to retrieve. /// The number of records per page. - /// An SQL builder object representing the base SQL query and its arguments. + /// An SQL builder object representing the SQL to retrieve the total number of records. + /// An SQL builder object representing the SQL to retrieve a single page of results. /// A Page of results. - Page Page(long page, long itemsPerPage, Sql sql); + Page Page(long page, long itemsPerPage, Sql sqlCount, Sql sqlPage); /// /// Retrieves a page of records and the total number of available records. @@ -570,10 +599,12 @@ public interface IQuery /// The Type representing a row in the result set. /// The 1-based page number to retrieve. /// The number of records per page. - /// An SQL builder object representing the SQL to retrieve the total number of records. - /// An SQL builder object representing the SQL to retrieve a single page of results. + /// The SQL to retrieve the total number of records. + /// Arguments to any embedded parameters in the sqlCount statement. + /// The SQL to retrieve a single page of results. + /// Arguments to any embedded parameters in the sqlPage statement. /// A Page of results. - Page Page(long page, long itemsPerPage, Sql sqlCount, Sql sqlPage); + Page Page(long page, long itemsPerPage, string sqlCount, object[] countArgs, string sqlPage, object[] pageArgs); #endregion @@ -600,10 +631,9 @@ public interface IQuery /// The Type representing a row in the result set. /// The number of rows at the start of the result set to skip over. /// The number of rows to retrieve. - /// The base SQL query. - /// Arguments to any embedded parameters in the SQL statement. + /// An SQL builder object representing the base SQL query and its arguments. /// A List of results. - List SkipTake(long skip, long take, string sql, params object[] args); + List SkipTake(long skip, long take, Sql sql); /// /// Retrieves a range of records from result set. @@ -614,9 +644,10 @@ public interface IQuery /// The Type representing a row in the result set. /// The number of rows at the start of the result set to skip over. /// The number of rows to retrieve. - /// An SQL builder object representing the base SQL query and its arguments. + /// The base SQL query. + /// Arguments to any embedded parameters in the SQL statement. /// A List of results. - List SkipTake(long skip, long take, Sql sql); + List SkipTake(long skip, long take, string sql, params object[] args); #endregion @@ -658,37 +689,29 @@ public interface IQuery /// Runs a query that should always return a single row. /// /// - /// Throws an exception if there is not exactly one record + /// Throws an exception if there is not exactly one matching record /// /// The Type representing a row in the result set. - /// The SQL query. - /// Arguments to any embedded parameters in the SQL statement. + /// An SQL builder object representing the query and its arguments. /// The single record matching the specified SQL query. - T Single(string sql, params object[] args); + T Single(Sql sql); /// /// Runs a query that should always return a single row. /// /// - /// Throws an exception if there is not exactly one matching record + /// Throws an exception if there is not exactly one record /// /// The Type representing a row in the result set. - /// An SQL builder object representing the query and its arguments. + /// The SQL query. + /// Arguments to any embedded parameters in the SQL statement. /// The single record matching the specified SQL query. - T Single(Sql sql); + T Single(string sql, params object[] args); #endregion #region SingleOrDefault - /// - /// Runs a query that should always return either a single row, or no rows. - /// - /// The Type representing a row in the result set. - /// An SQL builder object representing the query and its arguments. - /// The single record matching the specified primary key value, or default(T) if no matching rows. - T SingleOrDefault(Sql sql); - /// /// Returns the record with the specified primary key value, or the default value if not found. /// @@ -700,6 +723,14 @@ public interface IQuery /// The single record matching the specified primary key value. T SingleOrDefault(object primaryKey); + /// + /// Runs a query that should always return either a single row, or no rows. + /// + /// The Type representing a row in the result set. + /// An SQL builder object representing the query and its arguments. + /// The single record matching the specified primary key value, or default(T) if no matching rows. + T SingleOrDefault(Sql sql); + /// /// Runs a query that should always return either a single row, or no rows. /// @@ -717,18 +748,18 @@ public interface IQuery /// Runs a query that should always return at least one record. /// /// The Type representing a row in the result set. - /// The SQL query. - /// Arguments to any embedded parameters in the SQL statement. + /// An SQL builder object representing the query and its arguments. /// The first record in the result set. - T First(string sql, params object[] args); + T First(Sql sql); /// /// Runs a query that should always return at least one record. /// /// The Type representing a row in the result set. - /// An SQL builder object representing the query and its arguments. + /// The SQL query. + /// Arguments to any embedded parameters in the SQL statement. /// The first record in the result set. - T First(Sql sql); + T First(string sql, params object[] args); #endregion @@ -738,37 +769,18 @@ public interface IQuery /// Runs a query and returns the first record, or the default value if no matching records. /// /// The Type representing a row in the result set. - /// The SQL query. - /// Arguments to any embedded parameters in the SQL statement. + /// An SQL builder object representing the query and its arguments. /// The first record in the result set, or default(T) if no matching rows. - T FirstOrDefault(string sql, params object[] args); + T FirstOrDefault(Sql sql); /// /// Runs a query and returns the first record, or the default value if no matching records. /// /// The Type representing a row in the result set. - /// An SQL builder object representing the query and its arguments. + /// The SQL query. + /// Arguments to any embedded parameters in the SQL statement. /// The first record in the result set, or default(T) if no matching rows. - T FirstOrDefault(Sql sql); - - #endregion - - #region QueryMultiple - - /// - /// Perform a multi-results set query. - /// - /// An SQL builder object representing the query and its arguments. - /// A GridReader to be queried. - IGridReader QueryMultiple(Sql sql); - - /// - /// Perform a multi-results set query. - /// - /// The SQL query to be executed. - /// Arguments to any embedded parameters in the SQL. - /// A GridReader to be queried. - IGridReader QueryMultiple(string sql, params object[] args); + T FirstOrDefault(string sql, params object[] args); #endregion } diff --git a/PetaPoco/IQueryAsync.cs b/PetaPoco/IQueryAsync.cs index 1d033b56..1dd74562 100644 --- a/PetaPoco/IQueryAsync.cs +++ b/PetaPoco/IQueryAsync.cs @@ -9,131 +9,151 @@ namespace PetaPoco #if ASYNC public interface IQueryAsync { - #region Query + #region QueryAsync : Single-Poco /// /// Async version of . /// - Task QueryAsync(Action receivePocoCallback); + Task> QueryAsync(); /// - /// Async version of . + /// Async version of . /// - Task QueryAsync(Action receivePocoCallback, CommandType commandType); + Task> QueryAsync(Sql sql); /// - /// Async version of . + /// Async version of . /// - Task QueryAsync(Action receivePocoCallback, CancellationToken cancellationToken); + Task> QueryAsync(string sql, params object[] args); /// /// Async version of . /// - Task QueryAsync(Action receivePocoCallback, CancellationToken cancellationToken, CommandType commandType); + Task> QueryAsync(CancellationToken cancellationToken); /// - /// Async version of . + /// Async version of . /// - Task QueryAsync(Action receivePocoCallback, string sql, params object[] args); + Task> QueryAsync(CancellationToken cancellationToken, Sql sql); /// /// Async version of . /// - Task QueryAsync(Action receivePocoCallback, CommandType commandType, string sql, params object[] args); + Task> QueryAsync(CancellationToken cancellationToken, string sql, params object[] args); + + #endregion + + #region QueryAsync : Single-Poco as CommandType /// - /// Async version of . + /// Async version of . /// - Task QueryAsync(Action receivePocoCallback, CancellationToken cancellationToken, string sql, params object[] args); + Task> QueryAsync(CommandType commandType); /// - /// Async version of . + /// Async version of . /// - Task QueryAsync(Action receivePocoCallback, CancellationToken cancellationToken, CommandType commandType, string sql, params object[] args); + Task> QueryAsync(CommandType commandType, Sql sql); /// - /// Async version of . + /// Async version of . /// - Task QueryAsync(Action receivePocoCallback, Sql sql); + Task> QueryAsync(CommandType commandType, string sql, params object[] args); /// - /// Async version of . + /// Async version of . /// - Task QueryAsync(Action receivePocoCallback, CommandType commandType, Sql sql); + Task> QueryAsync(CancellationToken cancellationToken, CommandType commandType); /// /// Async version of . /// - Task QueryAsync(Action receivePocoCallback, CancellationToken cancellationToken, Sql sql); + Task> QueryAsync(CancellationToken cancellationToken, CommandType commandType, Sql sql); /// - /// Async version of . + /// Async version of . /// - Task QueryAsync(Action receivePocoCallback, CancellationToken cancellationToken, CommandType commandType, Sql sql); + Task> QueryAsync(CancellationToken cancellationToken, CommandType commandType, string sql, params object[] args); + + #endregion + + #region QueryAsync with Action : Single-Poco /// /// Async version of . /// - Task> QueryAsync(); + Task QueryAsync(Action receivePocoCallback); /// - /// Async version of . + /// Async version of . /// - Task> QueryAsync(CommandType commandType); + Task QueryAsync(Action receivePocoCallback, Sql sql); /// - /// Async version of . + /// Async version of . /// - Task> QueryAsync(CancellationToken cancellationToken); + Task QueryAsync(Action receivePocoCallback, string sql, params object[] args); /// /// Async version of . /// - Task> QueryAsync(CancellationToken cancellationToken, CommandType commandType); + Task QueryAsync(Action receivePocoCallback, CancellationToken cancellationToken); /// - /// Async version of . + /// Async version of . /// - Task> QueryAsync(string sql, params object[] args); + Task QueryAsync(Action receivePocoCallback, CancellationToken cancellationToken, Sql sql); /// /// Async version of . /// - Task> QueryAsync(CommandType commandType, string sql, params object[] args); + Task QueryAsync(Action receivePocoCallback, CancellationToken cancellationToken, string sql, params object[] args); + + #endregion + + #region QueryAsync with Action : Single-Poco as CommandType /// - /// Async version of . + /// Async version of . /// - Task> QueryAsync(CancellationToken cancellationToken, string sql, params object[] args); + Task QueryAsync(Action receivePocoCallback, CommandType commandType); /// - /// Async version of . + /// Async version of . /// - Task> QueryAsync(CancellationToken cancellationToken, CommandType commandType, string sql, params object[] args); + Task QueryAsync(Action receivePocoCallback, CommandType commandType, Sql sql); /// - /// Async version of . + /// Async version of . /// - Task> QueryAsync(Sql sql); + Task QueryAsync(Action receivePocoCallback, CommandType commandType, string sql, params object[] args); /// - /// Async version of . + /// Async version of . /// - Task> QueryAsync(CommandType commandType, Sql sql); + Task QueryAsync(Action receivePocoCallback, CancellationToken cancellationToken, CommandType commandType); /// /// Async version of . /// - Task> QueryAsync(CancellationToken cancellationToken, Sql sql); + Task QueryAsync(Action receivePocoCallback, CancellationToken cancellationToken, CommandType commandType, Sql sql); /// - /// Async version of . + /// Async version of . /// - Task> QueryAsync(CancellationToken cancellationToken, CommandType commandType, Sql sql); + Task QueryAsync(Action receivePocoCallback, CancellationToken cancellationToken, CommandType commandType, string sql, params object[] args); + + #endregion + + #region QueryAsync : Multi-Poco + + #endregion + + #region QueryMultipleAsync : Multi-POCO Result Set #endregion - #region Fetch + #region FetchAsync : Single-Poco /// /// Async version of . @@ -141,59 +161,71 @@ public interface IQueryAsync Task> FetchAsync(); /// - /// Async version of . + /// Async version of . /// - Task> FetchAsync(CommandType commandType); + Task> FetchAsync(Sql sql); /// - /// Async version of . + /// Async version of . /// - Task> FetchAsync(CancellationToken cancellationToken); + Task> FetchAsync(string sql, params object[] args); /// /// Async version of . /// - Task> FetchAsync(CancellationToken cancellationToken, CommandType commandType); + Task> FetchAsync(CancellationToken cancellationToken); /// - /// Async version of . + /// Async version of . /// - Task> FetchAsync(string sql, params object[] args); + Task> FetchAsync(CancellationToken cancellationToken, Sql sql); /// /// Async version of . /// - Task> FetchAsync(CommandType commandType, string sql, params object[] args); + Task> FetchAsync(CancellationToken cancellationToken, string sql, params object[] args); + + #endregion + + #region FetchAsync : Single-Poco as CommandType /// /// Async version of . /// - Task> FetchAsync(CancellationToken cancellationToken, string sql, params object[] args); + Task> FetchAsync(CommandType commandType); /// /// Async version of . /// - Task> FetchAsync(CancellationToken cancellationToken, CommandType commandType, string sql, params object[] args); + Task> FetchAsync(CommandType commandType, Sql sql); /// - /// Async version of . + /// Async version of . /// - Task> FetchAsync(Sql sql); + Task> FetchAsync(CommandType commandType, string sql, params object[] args); /// /// Async version of . /// - Task> FetchAsync(CommandType commandType, Sql sql); + Task> FetchAsync(CancellationToken cancellationToken, CommandType commandType); /// /// Async version of . /// - Task> FetchAsync(CancellationToken cancellationToken, Sql sql); + Task> FetchAsync(CancellationToken cancellationToken, CommandType commandType, Sql sql); /// /// Async version of . /// - Task> FetchAsync(CancellationToken cancellationToken, CommandType commandType, Sql sql); + Task> FetchAsync(CancellationToken cancellationToken, CommandType commandType, string sql, params object[] args); + + #endregion + + #region FetchAsync : Multi-Poco + + #endregion + + #region FetchAsync : Paged SkipTake /// /// Async version of . @@ -201,9 +233,9 @@ public interface IQueryAsync Task> FetchAsync(long page, long itemsPerPage); /// - /// Async version of . + /// Async version of . /// - Task> FetchAsync(CancellationToken cancellationToken, long page, long itemsPerPage); + Task> FetchAsync(long page, long itemsPerPage, Sql sql); /// /// Async version of . @@ -211,33 +243,23 @@ public interface IQueryAsync Task> FetchAsync(long page, long itemsPerPage, string sql, params object[] args); /// - /// Async version of . + /// Async version of . /// - Task> FetchAsync(CancellationToken cancellationToken, long page, long itemsPerPage, string sql, params object[] args); + Task> FetchAsync(CancellationToken cancellationToken, long page, long itemsPerPage); /// /// Async version of . /// - Task> FetchAsync(long page, long itemsPerPage, Sql sql); + Task> FetchAsync(CancellationToken cancellationToken, long page, long itemsPerPage, Sql sql); /// /// Async version of . /// - Task> FetchAsync(CancellationToken cancellationToken, long page, long itemsPerPage, Sql sql); + Task> FetchAsync(CancellationToken cancellationToken, long page, long itemsPerPage, string sql, params object[] args); #endregion - #region Page - - /// - /// Async version of . - /// - Task> PageAsync(long page, long itemsPerPage, string sqlCount, object[] countArgs, string sqlPage, object[] pageArgs); - - /// - /// Async version of . - /// - Task> PageAsync(CancellationToken cancellationToken, long page, long itemsPerPage, string sqlCount, object[] countArgs, string sqlPage, object[] pageArgs); + #region PageAsync /// /// Async version of . @@ -245,9 +267,9 @@ public interface IQueryAsync Task> PageAsync(long page, long itemsPerPage); /// - /// Async version of . + /// Async version of . /// - Task> PageAsync(CancellationToken cancellationToken, long page, long itemsPerPage); + Task> PageAsync(long page, long itemsPerPage, Sql sql); /// /// Async version of . @@ -255,14 +277,19 @@ public interface IQueryAsync Task> PageAsync(long page, long itemsPerPage, string sql, params object[] args); /// - /// Async version of . + /// Async version of . /// - Task> PageAsync(CancellationToken cancellationToken, long page, long itemsPerPage, string sql, params object[] args); + Task> PageAsync(long page, long itemsPerPage, Sql sqlCount, Sql sqlPage); /// - /// Async version of . + /// Async version of . /// - Task> PageAsync(long page, long itemsPerPage, Sql sql); + Task> PageAsync(long page, long itemsPerPage, string sqlCount, object[] countArgs, string sqlPage, object[] pageArgs); + + /// + /// Async version of . + /// + Task> PageAsync(CancellationToken cancellationToken, long page, long itemsPerPage); /// /// Async version of . @@ -270,18 +297,23 @@ public interface IQueryAsync Task> PageAsync(CancellationToken cancellationToken, long page, long itemsPerPage, Sql sql); /// - /// Async version of . + /// Async version of . /// - Task> PageAsync(long page, long itemsPerPage, Sql sqlCount, Sql sqlPage); + Task> PageAsync(CancellationToken cancellationToken, long page, long itemsPerPage, string sql, params object[] args); /// /// Async version of . /// Task> PageAsync(CancellationToken cancellationToken, long page, long itemsPerPage, Sql sqlCount, Sql sqlPage); + /// + /// Async version of . + /// + Task> PageAsync(CancellationToken cancellationToken, long page, long itemsPerPage, string sqlCount, object[] countArgs, string sqlPage, object[] pageArgs); + #endregion - #region SkipTake + #region SkipTakeAsync /// /// Async version of . @@ -289,9 +321,9 @@ public interface IQueryAsync Task> SkipTakeAsync(long skip, long take); /// - /// Async version of . + /// Async version of . /// - Task> SkipTakeAsync(CancellationToken cancellationToken, long skip, long take); + Task> SkipTakeAsync(long skip, long take, Sql sql); /// /// Async version of . @@ -299,23 +331,23 @@ public interface IQueryAsync Task> SkipTakeAsync(long skip, long take, string sql, params object[] args); /// - /// Async version of . + /// Async version of . /// - Task> SkipTakeAsync(CancellationToken cancellationToken, long skip, long take, string sql, params object[] args); + Task> SkipTakeAsync(CancellationToken cancellationToken, long skip, long take); /// /// Async version of . /// - Task> SkipTakeAsync(long skip, long take, Sql sql); + Task> SkipTakeAsync(CancellationToken cancellationToken, long skip, long take, Sql sql); /// - /// Async version of . + /// Async version of . /// - Task> SkipTakeAsync(CancellationToken cancellationToken, long skip, long take, Sql sql); + Task> SkipTakeAsync(CancellationToken cancellationToken, long skip, long take, string sql, params object[] args); #endregion - #region Exists + #region ExistsAsync /// /// Async version of . @@ -323,14 +355,14 @@ public interface IQueryAsync Task ExistsAsync(object primaryKey); /// - /// Async version of . + /// Async version of . /// - Task ExistsAsync(CancellationToken cancellationToken, object primaryKey); + Task ExistsAsync(string sqlCondition, params object[] args); /// - /// Async version of . + /// Async version of . /// - Task ExistsAsync(string sqlCondition, params object[] args); + Task ExistsAsync(CancellationToken cancellationToken, object primaryKey); /// /// Async version of . @@ -339,7 +371,7 @@ public interface IQueryAsync #endregion - #region Single + #region SingleAsync /// /// Async version of . @@ -347,9 +379,9 @@ public interface IQueryAsync Task SingleAsync(object primaryKey); /// - /// Async version of . + /// Async version of . /// - Task SingleAsync(CancellationToken cancellationToken, object primaryKey); + Task SingleAsync(Sql sql); /// /// Async version of . @@ -357,38 +389,38 @@ public interface IQueryAsync Task SingleAsync(string sql, params object[] args); /// - /// Async version of . + /// Async version of . /// - Task SingleAsync(CancellationToken cancellationToken, string sql, params object[] args); + Task SingleAsync(CancellationToken cancellationToken, object primaryKey); /// /// Async version of . /// - Task SingleAsync(Sql sql); + Task SingleAsync(CancellationToken cancellationToken, Sql sql); /// - /// Async version of . + /// Async version of . /// - Task SingleAsync(CancellationToken cancellationToken, Sql sql); + Task SingleAsync(CancellationToken cancellationToken, string sql, params object[] args); #endregion - #region SingleOrDefault + #region SingleOrDefaultAsync /// - /// Async version of . + /// Async version of . /// - Task SingleOrDefaultAsync(Sql sql); + Task SingleOrDefaultAsync(object primaryKey); /// /// Async version of . /// - Task SingleOrDefaultAsync(CancellationToken cancellationToken, Sql sql); + Task SingleOrDefaultAsync(Sql sql); /// - /// Async version of . + /// Async version of . /// - Task SingleOrDefaultAsync(object primaryKey); + Task SingleOrDefaultAsync(string sql, params object[] args); /// /// Async version of . @@ -396,9 +428,9 @@ public interface IQueryAsync Task SingleOrDefaultAsync(CancellationToken cancellationToken, object primaryKey); /// - /// Async version of . + /// Async version of . /// - Task SingleOrDefaultAsync(string sql, params object[] args); + Task SingleOrDefaultAsync(CancellationToken cancellationToken, Sql sql); /// /// Async version of . @@ -407,55 +439,51 @@ public interface IQueryAsync #endregion - #region First + #region FirstAsync /// - /// Async version of . + /// Async version of . /// - Task FirstAsync(string sql, params object[] args); + Task FirstAsync(Sql sql); /// /// Async version of . /// - Task FirstAsync(CancellationToken cancellationToken, string sql, params object[] args); + Task FirstAsync(string sql, params object[] args); /// /// Async version of . /// - Task FirstAsync(Sql sql); + Task FirstAsync(CancellationToken cancellationToken, Sql sql); /// - /// Async version of . + /// Async version of . /// - Task FirstAsync(CancellationToken cancellationToken, Sql sql); + Task FirstAsync(CancellationToken cancellationToken, string sql, params object[] args); #endregion - #region FirstOrDefault + #region FirstOrDefaultAsync /// - /// Async version of . + /// Async version of . /// - Task FirstOrDefaultAsync(string sql, params object[] args); + Task FirstOrDefaultAsync(Sql sql); /// /// Async version of . /// - Task FirstOrDefaultAsync(CancellationToken cancellationToken, string sql, params object[] args); + Task FirstOrDefaultAsync(string sql, params object[] args); /// /// Async version of . /// - Task FirstOrDefaultAsync(Sql sql); + Task FirstOrDefaultAsync(CancellationToken cancellationToken, Sql sql); /// - /// Async version of . + /// Async version of . /// - Task FirstOrDefaultAsync(CancellationToken cancellationToken, Sql sql); - - #endregion - - #region QueryMultiple + Task FirstOrDefaultAsync(CancellationToken cancellationToken, string sql, params object[] args); #endregion } diff --git a/PetaPoco/IStoredProc.cs b/PetaPoco/IStoredProc.cs index 7dbc7ccf..54e0830d 100644 --- a/PetaPoco/IStoredProc.cs +++ b/PetaPoco/IStoredProc.cs @@ -8,50 +8,50 @@ namespace PetaPoco public interface IStoredProc { /// - /// Executes a stored procedure and returns the result as an IEnumerable of type T. + /// Executes a non-query stored procedure and returns the number of rows affected. /// /// /// For any arguments which are POCOs, each readable property will be turned into a named parameter for the stored procedure. Arguments which are IDbDataParameters will be passed through. Any other argument types will throw an exception. /// - /// The Type representing a row in the result set. /// The name of the stored procedure to execute. /// The arguments to pass to the stored procedure. - /// An IEnumerable of type T containing the result set of the stored procedure. - IEnumerable QueryProc(string storedProcedureName, params object[] args); + /// The number of rows affected by the stored procedure. + int ExecuteNonQueryProc(string storedProcedureName, params object[] args); /// - /// Executes a stored procedure and returns the result as a List of type T. + /// Executes a stored procedure and returns the first column of the first row in the result set as type T. /// /// /// For any arguments which are POCOs, each readable property will be turned into a named parameter for the stored procedure. Arguments which are IDbDataParameters will be passed through. Any other argument types will throw an exception. /// - /// The Type representing a row in the result set. + /// The type that the result value should be cast to. /// The name of the stored procedure to execute. /// The arguments to pass to the stored procedure. - /// A List of type T containing the result set of the stored procedure. - List FetchProc(string storedProcedureName, params object[] args); + /// The scalar result of the stored procedure of type T. + T ExecuteScalarProc(string storedProcedureName, params object[] args); /// - /// Executes a stored procedure and returns the first column of the first row in the result set as type T. + /// Executes a stored procedure and returns the result as an IEnumerable of type T. /// /// /// For any arguments which are POCOs, each readable property will be turned into a named parameter for the stored procedure. Arguments which are IDbDataParameters will be passed through. Any other argument types will throw an exception. /// - /// The type that the result value should be cast to. + /// The Type representing a row in the result set. /// The name of the stored procedure to execute. /// The arguments to pass to the stored procedure. - /// The scalar result of the stored procedure of type T. - T ExecuteScalarProc(string storedProcedureName, params object[] args); + /// An IEnumerable of type T containing the result set of the stored procedure. + IEnumerable QueryProc(string storedProcedureName, params object[] args); /// - /// Executes a non-query stored procedure and returns the number of rows affected. + /// Executes a stored procedure and returns the result as a List of type T. /// /// /// For any arguments which are POCOs, each readable property will be turned into a named parameter for the stored procedure. Arguments which are IDbDataParameters will be passed through. Any other argument types will throw an exception. /// + /// The Type representing a row in the result set. /// The name of the stored procedure to execute. /// The arguments to pass to the stored procedure. - /// The number of rows affected by the stored procedure. - int ExecuteNonQueryProc(string storedProcedureName, params object[] args); + /// A List of type T containing the result set of the stored procedure. + List FetchProc(string storedProcedureName, params object[] args); } } diff --git a/PetaPoco/IStoredProcAsync.cs b/PetaPoco/IStoredProcAsync.cs index 10f199d7..b9e6b9ff 100644 --- a/PetaPoco/IStoredProcAsync.cs +++ b/PetaPoco/IStoredProcAsync.cs @@ -11,44 +11,48 @@ namespace PetaPoco /// public interface IStoredProcAsync { + /// + Task ExecuteNonQueryProcAsync(string storedProcedureName, params object[] args); + + /// + Task ExecuteScalarProcAsync(string storedProcedureName, params object[] args); + + /// + Task> QueryProcAsync(string storedProcedureName, params object[] args); + /// Task QueryProcAsync(Action receivePocoCallback, string storedProcedureName, params object[] args); + /// + Task> FetchProcAsync(string storedProcedureName, params object[] args); + /// - /// Asynchronously executes a stored procedure and returns the result as an IAsyncReader of type T. + /// Asynchronously executes a non-query stored procedure and returns the number of rows affected. /// /// /// For any arguments which are POCOs, each readable property will be turned into a named parameter for the stored procedure. Arguments which are IDbDataParameters will be passed through. Any other argument types will throw an exception. /// - /// The Type representing a row in the result set. - /// An action callback to execute on each POCO in the result set. /// A cancellation token that can be used to cancel the operation. /// The name of the stored procedure to execute. /// The arguments to pass to the stored procedure. - /// A task representing the asynchronous operation. The task result is an IAsyncReader of type T containing the result set of the stored procedure. - Task QueryProcAsync(Action receivePocoCallback, CancellationToken cancellationToken, string storedProcedureName, params object[] args); - - /// - Task> QueryProcAsync(string storedProcedureName, params object[] args); + /// A task representing the asynchronous operation. The task result is the number of rows affected by the stored procedure. + Task ExecuteNonQueryProcAsync(CancellationToken cancellationToken, string storedProcedureName, params object[] args); /// - /// Asynchronously executes a stored procedure and returns the result as an IAsyncReader of type T. + /// Asynchronously executes a stored procedure and returns the first column of the first row in the result set as type T. /// /// /// For any arguments which are POCOs, each readable property will be turned into a named parameter for the stored procedure. Arguments which are IDbDataParameters will be passed through. Any other argument types will throw an exception. /// - /// The Type representing a row in the result set. + /// The type that the result value should be cast to. /// A cancellation token that can be used to cancel the operation. /// The name of the stored procedure to execute. /// The arguments to pass to the stored procedure. - /// A task representing the asynchronous operation. The task result is an IAsyncReader of type T containing the result set of the stored procedure. - Task> QueryProcAsync(CancellationToken cancellationToken, string storedProcedureName, params object[] args); - - /// - Task> FetchProcAsync(string storedProcedureName, params object[] args); + /// A task representing the asynchronous operation. The task result is the scalar result of the stored procedure of type T. + Task ExecuteScalarProcAsync(CancellationToken cancellationToken, string storedProcedureName, params object[] args); /// - /// Asynchronously executes a stored procedure and returns the result as a List of type T. + /// Asynchronously executes a stored procedure and returns the result as an IAsyncReader of type T. /// /// /// For any arguments which are POCOs, each readable property will be turned into a named parameter for the stored procedure. Arguments which are IDbDataParameters will be passed through. Any other argument types will throw an exception. @@ -57,39 +61,35 @@ public interface IStoredProcAsync /// A cancellation token that can be used to cancel the operation. /// The name of the stored procedure to execute. /// The arguments to pass to the stored procedure. - /// A task representing the asynchronous operation. The task result is a List of type T containing the result set of the stored procedure. - Task> FetchProcAsync(CancellationToken cancellationToken, string storedProcedureName, params object[] args); - - /// - Task ExecuteScalarProcAsync(string storedProcedureName, params object[] args); + /// A task representing the asynchronous operation. The task result is an IAsyncReader of type T containing the result set of the stored procedure. + Task> QueryProcAsync(CancellationToken cancellationToken, string storedProcedureName, params object[] args); /// - /// Asynchronously executes a stored procedure and returns the first column of the first row in the result set as type T. + /// Asynchronously executes a stored procedure and returns the result as an IAsyncReader of type T. /// /// /// For any arguments which are POCOs, each readable property will be turned into a named parameter for the stored procedure. Arguments which are IDbDataParameters will be passed through. Any other argument types will throw an exception. /// - /// The type that the result value should be cast to. + /// The Type representing a row in the result set. + /// An action callback to execute on each POCO in the result set. /// A cancellation token that can be used to cancel the operation. /// The name of the stored procedure to execute. /// The arguments to pass to the stored procedure. - /// A task representing the asynchronous operation. The task result is the scalar result of the stored procedure of type T. - Task ExecuteScalarProcAsync(CancellationToken cancellationToken, string storedProcedureName, params object[] args); - - /// - Task ExecuteNonQueryProcAsync(string storedProcedureName, params object[] args); + /// A task representing the asynchronous operation. The task result is an IAsyncReader of type T containing the result set of the stored procedure. + Task QueryProcAsync(Action receivePocoCallback, CancellationToken cancellationToken, string storedProcedureName, params object[] args); /// - /// Asynchronously executes a non-query stored procedure and returns the number of rows affected. + /// Asynchronously executes a stored procedure and returns the result as a List of type T. /// /// /// For any arguments which are POCOs, each readable property will be turned into a named parameter for the stored procedure. Arguments which are IDbDataParameters will be passed through. Any other argument types will throw an exception. /// + /// The Type representing a row in the result set. /// A cancellation token that can be used to cancel the operation. /// The name of the stored procedure to execute. /// The arguments to pass to the stored procedure. - /// A task representing the asynchronous operation. The task result is the number of rows affected by the stored procedure. - Task ExecuteNonQueryProcAsync(CancellationToken cancellationToken, string storedProcedureName, params object[] args); + /// A task representing the asynchronous operation. The task result is a List of type T containing the result set of the stored procedure. + Task> FetchProcAsync(CancellationToken cancellationToken, string storedProcedureName, params object[] args); } #endif } diff --git a/PetaPoco/Utilities/AsyncReader.cs b/PetaPoco/Utilities/AsyncReader.cs index b1bb0fe7..485794fd 100644 --- a/PetaPoco/Utilities/AsyncReader.cs +++ b/PetaPoco/Utilities/AsyncReader.cs @@ -14,8 +14,8 @@ public class AsyncReader : IAsyncReader { private readonly bool _isAsync; private readonly Func _pocoFactory; - private IDbCommand _cmd; private IDatabase _db; + private IDbCommand _cmd; private IDataReader _reader; private DbDataReader Reader => (DbDataReader)_reader; diff --git a/PetaPoco/Utilities/AutoSelectHelper.cs b/PetaPoco/Utilities/AutoSelectHelper.cs index 7a18f63d..1d85257d 100644 --- a/PetaPoco/Utilities/AutoSelectHelper.cs +++ b/PetaPoco/Utilities/AutoSelectHelper.cs @@ -9,7 +9,8 @@ internal static class AutoSelectHelper private static Regex rxSelect = new Regex(@"\A\s*(SELECT|EXECUTE|CALL|WITH|SET|DECLARE)\s", RegexOptions.Compiled | RegexOptions.Singleline | RegexOptions.IgnoreCase | RegexOptions.Multiline); - private static Regex rxFrom = new Regex(@"\A\s*FROM\s", RegexOptions.Compiled | RegexOptions.Singleline | RegexOptions.IgnoreCase | RegexOptions.Multiline); + private static Regex rxFrom = new Regex(@"\A\s*FROM\s", + RegexOptions.Compiled | RegexOptions.Singleline | RegexOptions.IgnoreCase | RegexOptions.Multiline); public static string AddSelectClause(IProvider provider, string sql, IMapper defaultMapper) { @@ -30,4 +31,4 @@ public static string AddSelectClause(IProvider provider, string sql, IMapper return sql; } } -} \ No newline at end of file +}