Skip to content

ReadAsync is sync-over-async #76

@vidaj

Description

@vidaj

From DbConnectionExtensions.cs:

 public static async Task<IEnumerable<T>> ReadAsync<T>(
           this IDbConnection dbConnection,
           CancellationToken cancellationToken,
           string query,
           object arguments = null, Action<IDbCommand> configureCommand = default)
        {
            using (var dataReader = await dbConnection.ExecuteReaderAsync(cancellationToken, query, arguments, configureCommand).ConfigureAwait(false))
            {
                SqlStatement.Current = query;
                return dataReader.Read<T>();
            }
        }

Here you can see that the only async functionality of ReadAsync is ExecuteReaderAsync.
The actual reading of the result is done synchronously and will block for every read.

I'm guessing this is done because IDataReader does not have any async methods available. The ReadAsync-methods are available when using DbDataReader but not through the IDataReader interface. This is most likely to avoid forcing any existing implementers of IDataReader to implement the async methods.

Hopefully, DbReader can check if dataReader is an instance of DbDataReader and then use the proper async Read methods and otherwise use the current sync-methods as a fallback when reader is not an instance of DbDataReader.

There is also an opportunity here to implement an async read method using IAsyncEnumerable instead of allocating a List and returning it as an IEnumerable - where most clients probably immediately calls .ToList() on it. This will also make queries that might return multiple values and the client uses .FirstOrDefault() more efficient since IAsyncEnumerable will only actually fetch and map the data that is iterated.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions