private async Task <IEnumerable <T> > ReadBufferedAsync <T>(int index, Func <IDataReader, object> deserializer, Identity typedIdentity) { try { var reader = (DbDataReader)this.reader; var buffer = new List <T>(); while (index == gridIndex && await reader.ReadAsync(cancel).ConfigureAwait(false)) { buffer.Add((T)deserializer(reader)); } return(buffer); } finally // finally so that First etc progresses things even when multiple rows { if (index == gridIndex) { await NextResultAsync().ConfigureAwait(false); } } }
internal GridReader(IDbCommand command, IDataReader reader, Identity identity, DynamicParameters dynamicParams, bool addToCache, CancellationToken cancel) : this(command, reader, identity, dynamicParams, addToCache) { this.cancel = cancel; }
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 <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)); } while (await reader.NextResultAsync().ConfigureAwait(false)) { } command.OnCompleted(); 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, command.Parameters); 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 IEnumerable <T> ReadDeferred <T>(int index, Func <IDataReader, object> deserializer, Identity typedIdentity) { try { while (index == gridIndex && reader.Read()) { yield return((T)deserializer(reader)); } } finally // finally so that First etc progresses things even when multiple rows { if (index == gridIndex) { NextResult(); } } }