private static async Task <IEnumerable <TReturn> > MultiMapAsync <TReturn>(this IDbConnection cnn, CommandDefinition command, Type[] types, Func <object[], TReturn> map, string splitOn) { if (types.Length < 1) { throw new ArgumentException("you must provide at least one type to deserialize"); } object param = command.Parameters; var identity = new Identity(command.CommandText, command.CommandType, cnn, types[0], param == null ? null : param.GetType(), types); var info = GetCacheInfo(identity, param, command.AddToCache); bool wasClosed = cnn.State == ConnectionState.Closed; try { if (wasClosed) { await((DbConnection)cnn).OpenAsync().ConfigureAwait(false); } using (var cmd = (DbCommand)command.SetupCommand(cnn, info.ParamReader)) using (var reader = await cmd.ExecuteReaderAsync(command.CancellationToken).ConfigureAwait(false)) { var results = MultiMapImpl <TReturn>(null, default(CommandDefinition), types, map, splitOn, reader, identity, true); return(command.Buffered ? results.ToList() : results); } } finally { if (wasClosed) { cnn.Close(); } } }
private static async Task <int> ExecuteImplAsync(IDbConnection cnn, CommandDefinition command, object param) { var identity = new Identity(command.CommandText, command.CommandType, cnn, null, param == null ? null : param.GetType(), null); var info = GetCacheInfo(identity, param, command.AddToCache); bool wasClosed = cnn.State == ConnectionState.Closed; using (var cmd = (DbCommand)command.SetupCommand(cnn, info.ParamReader)) { try { if (wasClosed) { await((DbConnection)cnn).OpenAsync(command.CancellationToken).ConfigureAwait(false); } var result = await cmd.ExecuteNonQueryAsync(command.CancellationToken).ConfigureAwait(false); command.OnCompleted(); return(result); } finally { if (wasClosed) { cnn.Close(); } } } }
private static async Task <IEnumerable <TReturn> > MultiMapAsync <TFirst, TSecond, TThird, TFourth, TFifth, TSixth, TSeventh, TReturn>(this IDbConnection cnn, CommandDefinition command, Delegate map, string splitOn) { object param = command.Parameters; var identity = new Identity(command.CommandText, command.CommandType, cnn, typeof(TFirst), param == null ? null : param.GetType(), new[] { typeof(TFirst), typeof(TSecond), typeof(TThird), typeof(TFourth), typeof(TFifth), typeof(TSixth), typeof(TSeventh) }); var info = GetCacheInfo(identity, param, command.AddToCache); bool wasClosed = cnn.State == ConnectionState.Closed; try { if (wasClosed) { await((DbConnection)cnn).OpenAsync(command.CancellationToken).ConfigureAwait(false); } using (var cmd = (DbCommand)command.SetupCommand(cnn, info.ParamReader)) using (var reader = await cmd.ExecuteReaderAsync(wasClosed ? CommandBehavior.CloseConnection | CommandBehavior.SequentialAccess : CommandBehavior.SequentialAccess, command.CancellationToken).ConfigureAwait(false)) { if (!command.Buffered) { wasClosed = false; // handing back open reader; rely on command-behavior } var results = MultiMapImpl <TFirst, TSecond, TThird, TFourth, TFifth, TSixth, TSeventh, TReturn>(null, CommandDefinition.ForCallback(command.Parameters), map, splitOn, reader, identity, true); return(command.Buffered ? results.ToList() : results); } } finally { if (wasClosed) { cnn.Close(); } } }
/// <summary> /// Execute a query asynchronously using .NET 4.5 Task. /// </summary> public static async Task <IEnumerable <T> > QueryAsync <T>(this IDbConnection cnn, CommandDefinition command) { object param = command.Parameters; var identity = new Identity(command.CommandText, command.CommandType, cnn, typeof(T), param == null ? null : param.GetType(), null); var info = GetCacheInfo(identity, param); bool wasClosed = cnn.State == ConnectionState.Closed; using (var cmd = (DbCommand)command.SetupCommand(cnn, info.ParamReader)) { try { if (wasClosed) { await((DbConnection)cnn).OpenAsync().ConfigureAwait(false); } using (var reader = await cmd.ExecuteReaderAsync(command.CancellationToken).ConfigureAwait(false)) { return(ExecuteReader <T>(reader, identity, info).ToList()); } } finally { if (wasClosed) { cnn.Close(); } } } }
private static async Task <IEnumerable <T> > QueryAsync <T>(this IDbConnection cnn, Type effectiveType, CommandDefinition command) { object param = command.Parameters; var identity = new Identity(command.CommandText, command.CommandType, cnn, effectiveType, param == null ? null : param.GetType(), null); var info = GetCacheInfo(identity, param, command.AddToCache); bool wasClosed = cnn.State == ConnectionState.Closed; var cancel = command.CancellationToken; using (var cmd = (DbCommand)command.SetupCommand(cnn, info.ParamReader)) { DbDataReader reader = null; try { if (wasClosed) { await((DbConnection)cnn).OpenAsync(cancel).ConfigureAwait(false); } reader = await cmd.ExecuteReaderAsync(wasClosed?CommandBehavior.CloseConnection | CommandBehavior.SequentialAccess : CommandBehavior.SequentialAccess, cancel).ConfigureAwait(false); var tuple = info.Deserializer; int hash = GetColumnHash(reader); if (tuple.Func == null || tuple.Hash != hash) { tuple = info.Deserializer = new DeserializerState(hash, GetDeserializer(effectiveType, reader, 0, -1, false)); if (command.AddToCache) { SetQueryCache(identity, info); } } var func = tuple.Func; if (command.Buffered) { List <T> buffer = new List <T>(); while (await reader.ReadAsync(cancel).ConfigureAwait(false)) { buffer.Add((T)func(reader)); } return(buffer); } else { // can't use ReadAsync / cancellation; but this will have to do wasClosed = false; // don't close if handing back an open reader; rely on the command-behavior var deferred = ExecuteReaderSync <T>(reader, func); reader = null; // to prevent it being disposed before the caller gets to see it return(deferred); } } finally { using (reader) { } // dispose if non-null if (wasClosed) { cnn.Close(); } } } }
private static async Task <IEnumerable <TReturn> > MultiMapAsync <TFirst, TSecond, TThird, TFourth, TFifth, TSixth, TSeventh, TReturn>(this IDbConnection cnn, CommandDefinition command, Delegate map, string splitOn) { object param = command.Parameters; var identity = new Identity(command.CommandText, command.CommandType, cnn, typeof(TFirst), param == null ? null : param.GetType(), new[] { typeof(TFirst), typeof(TSecond), typeof(TThird), typeof(TFourth), typeof(TFifth), typeof(TSixth), typeof(TSeventh) }); var info = GetCacheInfo(identity); bool wasClosed = cnn.State == ConnectionState.Closed; try { if (wasClosed) { await((DbConnection)cnn).OpenAsync(); } using (var cmd = (DbCommand)command.SetupCommand(cnn, info.ParamReader)) using (var reader = await cmd.ExecuteReaderAsync(command.CancellationToken)) { var results = MultiMapImpl <TFirst, TSecond, TThird, TFourth, TFifth, TSixth, TSeventh, TReturn>(null, default(CommandDefinition), map, splitOn, reader, identity); return(command.Buffered ? results.ToList() : results); } } finally { if (wasClosed) { cnn.Close(); } } }
/// <summary> /// Execute a command asynchronously using .NET 4.5 Task. /// </summary> public static async Task <int> ExecuteAsync(this IDbConnection cnn, CommandDefinition command) { object param = command.Parameters; var identity = new Identity(command.CommandText, command.CommandType, cnn, null, param == null ? null : param.GetType(), null); var info = GetCacheInfo(identity); bool wasClosed = cnn.State == ConnectionState.Closed; using (var cmd = (DbCommand)command.SetupCommand(cnn, info.ParamReader)) { try { if (wasClosed) { await((DbConnection)cnn).OpenAsync(); } return(await cmd.ExecuteNonQueryAsync(command.CancellationToken)); } finally { if (wasClosed) { cnn.Close(); } } } }
private static async Task <IDataReader> ExecuteReaderImplAsync(IDbConnection cnn, CommandDefinition command) { Action <IDbCommand, object> paramReader = GetParameterReader(cnn, ref command); DbCommand cmd = null; bool wasClosed = cnn.State == ConnectionState.Closed; try { cmd = (DbCommand)command.SetupCommand(cnn, paramReader); if (wasClosed) { await((DbConnection)cnn).OpenAsync(command.CancellationToken).ConfigureAwait(false); } var reader = await cmd.ExecuteReaderAsync(wasClosed?CommandBehavior.CloseConnection | CommandBehavior.SequentialAccess : CommandBehavior.SequentialAccess, command.CancellationToken).ConfigureAwait(false); wasClosed = false; return(reader); } finally { if (wasClosed) { cnn.Close(); } if (cmd != null) { cmd.Dispose(); } } }
/// <summary> /// Execute a command that returns multiple result sets, and access each in turn /// </summary> public static async Task <GridReader> QueryMultipleAsync(this IDbConnection cnn, CommandDefinition command) { object param = command.Parameters; Identity identity = new Identity(command.CommandText, command.CommandType, cnn, typeof(GridReader), param == null ? null : param.GetType(), null); CacheInfo info = GetCacheInfo(identity, param, command.AddToCache); DbCommand cmd = null; IDataReader reader = null; bool wasClosed = cnn.State == ConnectionState.Closed; try { if (wasClosed) { await((DbConnection)cnn).OpenAsync(command.CancellationToken).ConfigureAwait(false); } cmd = (DbCommand)command.SetupCommand(cnn, info.ParamReader); reader = await cmd.ExecuteReaderAsync(wasClosed?CommandBehavior.CloseConnection | CommandBehavior.SequentialAccess : CommandBehavior.SequentialAccess, command.CancellationToken).ConfigureAwait(false); var result = new GridReader(cmd, reader, identity, command.Parameters as DynamicParameters, command.AddToCache, command.CancellationToken); wasClosed = false; // *if* the connection was closed and we got this far, then we now have a reader // with the CloseConnection flag, so the reader will deal with the connection; we // still need something in the "finally" to ensure that broken SQL still results // in the connection closing itself return(result); } catch { if (reader != null) { if (!reader.IsClosed) { try { cmd.Cancel(); } catch { /* don't spoil the existing exception */ } } reader.Dispose(); } if (cmd != null) { cmd.Dispose(); } if (wasClosed) { cnn.Close(); } throw; } }
/// <summary> /// 查询返回DataSet /// </summary> /// <param name="cnn"></param> /// <param name="adapter"></param> /// <param name="sql"></param> /// <param name="param"></param> /// <param name="transaction"></param> /// <param name="buffered"></param> /// <param name="commandTimeout"></param> /// <param name="commandType"></param> /// <returns></returns> public static DataSet QueryDataSet(this IDbConnection cnn, IDbDataAdapter adapter, string sql, object param = null, IDbTransaction transaction = null, bool buffered = true, int?commandTimeout = null, CommandType?commandType = null) { var ds = new DataSet(); var command = new CommandDefinition(cnn, sql, (object)param, transaction, commandTimeout, commandType, buffered ? CommandFlags.Buffered : CommandFlags.None); var identity = new Identity(command.CommandText, command.CommandType, cnn, null, param == null ? null : param.GetType(), null); var info = SqlMapper.GetCacheInfo(identity, param, command.AddToCache); bool wasClosed = cnn.State == ConnectionState.Closed; if (wasClosed) { cnn.Open(); } adapter.SelectCommand = command.SetupCommand(cnn, info.ParamReader); adapter.Fill(ds); if (wasClosed) { cnn.Close(); } return(ds); }
private async static Task <T> ExecuteScalarImplAsync <T>(IDbConnection cnn, CommandDefinition command) { Action <IDbCommand, object> paramReader = null; object param = command.Parameters; if (param != null) { var identity = new Identity(command.CommandText, command.CommandType, cnn, null, param.GetType(), null); paramReader = GetCacheInfo(identity, command.Parameters, command.AddToCache).ParamReader; } DbCommand cmd = null; bool wasClosed = cnn.State == ConnectionState.Closed; object result; try { cmd = (DbCommand)command.SetupCommand(cnn, paramReader); if (wasClosed) { await((DbConnection)cnn).OpenAsync(command.CancellationToken).ConfigureAwait(false); } result = await cmd.ExecuteScalarAsync(command.CancellationToken).ConfigureAwait(false); command.OnCompleted(); } finally { if (wasClosed) { cnn.Close(); } if (cmd != null) { cmd.Dispose(); } } return(Parse <T>(result)); }
/// <summary> /// 查询返回DataSet /// </summary> /// <param name="cnn"></param> /// <param name="adapter"></param> /// <param name="sql"></param> /// <param name="param"></param> /// <param name="transaction"></param> /// <param name="buffered"></param> /// <param name="commandTimeout"></param> /// <param name="commandType"></param> /// <param name="isExcludeUnitOfWork"></param> /// <returns></returns> public static async Task <DataSet> QueryDataSetAsync(this IDbConnection cnn, IDbDataAdapter adapter, string sql, object param = null, IDbTransaction transaction = null, bool buffered = true, int?commandTimeout = null, CommandType?commandType = null, bool isExcludeUnitOfWork = false) { var ds = new DataSet(); var command = new CommandDefinition(cnn, sql, (object)param, transaction, commandTimeout, commandType, buffered ? CommandFlags.Buffered : CommandFlags.None, isExcludeUnitOfWork: isExcludeUnitOfWork); var identity = new Identity(command.CommandText, command.CommandType, cnn, null, param == null ? null : param.GetType(), null); var info = SqlMapper.GetCacheInfo(identity, param, command.AddToCache); bool wasClosed = cnn.State == ConnectionState.Closed; var cancel = command.CancellationToken; if (wasClosed) { await cnn.TryOpenAsync(cancel).ConfigureAwait(false); } adapter.SelectCommand = command.SetupCommand(cnn, info.ParamReader); adapter.Fill(ds); if (wasClosed) { cnn.Close(); } return(ds); }
private static async Task <int> ExecuteMultiImplAsync(IDbConnection cnn, CommandDefinition command, IEnumerable multiExec) { bool isFirst = true; int total = 0; bool wasClosed = cnn.State == ConnectionState.Closed; try { if (wasClosed) { await((DbConnection)cnn).OpenAsync(command.CancellationToken).ConfigureAwait(false); } CacheInfo info = null; string masterSql = null; if ((command.Flags & CommandFlags.Pipelined) != 0) { const int MAX_PENDING = 100; var pending = new Queue <AsyncExecState>(MAX_PENDING); DbCommand cmd = null; try { foreach (var obj in multiExec) { if (isFirst) { isFirst = false; cmd = (DbCommand)command.SetupCommand(cnn, null); masterSql = cmd.CommandText; var identity = new Identity(command.CommandText, cmd.CommandType, cnn, null, obj.GetType(), null); info = GetCacheInfo(identity, obj, command.AddToCache); } else if (pending.Count >= MAX_PENDING) { var recycled = pending.Dequeue(); total += await recycled.Task.ConfigureAwait(false); cmd = recycled.Command; cmd.CommandText = masterSql; // because we do magic replaces on "in" etc cmd.Parameters.Clear(); // current code is Add-tastic } else { cmd = (DbCommand)command.SetupCommand(cnn, null); } info.ParamReader(cmd, obj); var task = cmd.ExecuteNonQueryAsync(command.CancellationToken); pending.Enqueue(new AsyncExecState(cmd, task)); cmd = null; // note the using in the finally: this avoids a double-dispose } while (pending.Count != 0) { var pair = pending.Dequeue(); using (pair.Command) { } // dispose commands total += await pair.Task.ConfigureAwait(false); } } finally { // this only has interesting work to do if there are failures using (cmd) { } // dispose commands while (pending.Count != 0) { // dispose tasks even in failure using (pending.Dequeue().Command) { } // dispose commands } } } else { using (var cmd = (DbCommand)command.SetupCommand(cnn, null)) { foreach (var obj in multiExec) { if (isFirst) { masterSql = cmd.CommandText; isFirst = false; var identity = new Identity(command.CommandText, cmd.CommandType, cnn, null, obj.GetType(), null); info = GetCacheInfo(identity, obj, command.AddToCache); } else { cmd.CommandText = masterSql; // because we do magic replaces on "in" etc cmd.Parameters.Clear(); // current code is Add-tastic } info.ParamReader(cmd, obj); total += await cmd.ExecuteNonQueryAsync(command.CancellationToken).ConfigureAwait(false); } } } command.OnCompleted(); } finally { if (wasClosed) { cnn.Close(); } } return(total); }
private static async Task <T> QueryFirstOrDefaultAsync <T>(this IDbConnection cnn, Type effectiveType, CommandDefinition command) { object param = command.Parameters; var identity = new Identity(command.CommandText, command.CommandType, cnn, effectiveType, param?.GetType(), null); var info = GetCacheInfo(identity, param, command.AddToCache); bool wasClosed = cnn.State == ConnectionState.Closed; var cancel = command.CancellationToken; using (var cmd = (DbCommand)command.SetupCommand(cnn, info.ParamReader)) { DbDataReader reader = null; try { if (wasClosed) { await((DbConnection)cnn).OpenAsync(cancel).ConfigureAwait(false); } reader = await cmd.ExecuteReaderAsync(wasClosed?CommandBehavior.CloseConnection | CommandBehavior.SequentialAccess : CommandBehavior.SequentialAccess, cancel).ConfigureAwait(false); T result = default(T); if (await reader.ReadAsync(cancel).ConfigureAwait(false)) { var tuple = info.Deserializer; int hash = GetColumnHash(reader); if (tuple.Func == null || tuple.Hash != hash) { tuple = info.Deserializer = new DeserializerState(hash, GetDeserializer(effectiveType, reader, 0, -1, false)); if (command.AddToCache) { SetQueryCache(identity, info); } } var func = tuple.Func; object val = func(reader); if (val == null || val is T) { result = (T)val; } else { var convertToType = Nullable.GetUnderlyingType(effectiveType) ?? effectiveType; result = (T)Convert.ChangeType(val, convertToType, CultureInfo.InvariantCulture); } while (await reader.ReadAsync(cancel).ConfigureAwait(false)) { } } while (await reader.NextResultAsync(cancel).ConfigureAwait(false)) { } return(result); } finally { using (reader) { } // dispose if non-null if (wasClosed) { cnn.Close(); } } } }