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;
 }
Example #3
0
        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);
        }
Example #4
0
        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();
         }
     }
 }