-
Notifications
You must be signed in to change notification settings - Fork 5.2k
Description
Provider implementation tracking issues
- SqlClient: Implement async transaction begin/commit/rollback methods SqlClient#113
- Npgsql: Override new async methods introduced in corefx npgsql/npgsql#2481
- MySqlConnector: Implement new async methods coming in .NET Core 3.0 mysql-net/MySqlConnector#642
Specification
This issue consolidates #18225, #24244.
There are several APIs in System.Data.Common which possibly involve I/O, where we're missing async APIs altogether. This proposal adds these missing APIs, with default implementations that call the sync counterparts - much like the existing async methods on those APIs. In addition, all System.Data.Common types that implement IDisposable would be updated to implement IAsyncDisposable as well.
Note that in other cases async methods already exist but return Task, and we'd like to add overloads returning ValueTask. This is out of scope for this issue (but we'll work on these soon, see #19858, #25297).
This would ideally go into .NET Standard 2.1.
Proposal:
class DbConnection : IAsyncDisposable
{
protected virtual ValueTask<DbTransaction> BeginDbTransactionAsync(IsolationLevel isolationLevel, CancellationToken cancellationToken);
// The following delegate to BeginDbTransactionAsync, like their sync counterparts
public ValueTask<DbTransaction> BeginTransactionAsync(CancellationToken cancellationToken = default);
public ValueTask<DbTransaction> BeginTransactionAsync(IsolationLevel isolationLevel, CancellationToken cancellationToken = default);
public virtual Task ChangeDatabaseAsync(string databaseName, CancellationToken cancellationToken = default);
public virtual Task CloseAsync(CancellationToken cancellationToken = default);
public virtual ValueTask DisposeAsync();
}
class DbTransaction : IAsyncDisposable
{
public virtual Task CommitAsync(CancellationToken cancellationToken = default);
public virtual Task RollbackAsync(CancellationToken cancellationToken = default);
public virtual ValueTask DisposeAsync();
}
class DbCommand : IAsyncDisposable
{
public virtual Task PrepareAsync(CancellationToken cancellationToken = default);
public virtual ValueTask DisposeAsync();
}
class DbDataReader : IAsyncDisposable
{
public virtual Task CloseAsync(CancellationToken cancellationToken = default);
public virtual ValueTask DisposeAsync();
}
Note that this is only about adding async methods where non currently exist. #25297 is about adding ValueTask overloads where Task-returning async methods already exist (and where we have to think about naming etc.).
Returning Task vs. ValueTask
For the return value of the new proposed methods, our current guiding principle has been to opt for Task when the method in question represents a full database roundtrip operation, where any perf advantages of ValueTask are likely to be dominated by networking etc. Thus, method such as CommitAsync()
and RollbackAsync()
would return Task (aside from them having no return value).
Methods used for processing a resultset being streamed do seem like they'd benefit from returning ValueTask; examples include DbDataReader.ReadAsync()
, DbDataReader.GetFieldValueAsync<T>()
, which are out of scope of this proposal.
Cases such as DbConnection.CloseAsync()
and DbDataReader.CloseAsync()
seem to be between the two and we could probably go either way with them.
It would definitely be good to get some input on this.
Cancellation token overloads
Existing async methods in System.Data.Common come in pairs - a virtual one accepting CancellationToken and a non-virtual one delegating to the first. For the new methods we can just add one method with cancellation token defaulting to CancellationToken.None
.
/cc @divega @ajcvickers @terrajobst @stephentoub @bgrainger
Edit history
Date | Modification |
---|---|
16/4 | DbConnection.Open() returns Task instead of ValueTask as per @terrajobst's question |
18/4 | Added DbDataReader.Get{Stream,TextReader}Async() |
18/4 | Removed DbDataReader.Get{Stream,TextReader}Async() again (GetFieldValueAsync<T>() ) already provides this functionality) |
18/4 | Removed DbCommand.CancelAsync() |
15/5 | Changed BeginTransactionAsync() overloads to return ValueTask instead of Task, and changed to use the standard ADO.NET API pattern, as per design review. Changed DbDataReader.Close() to return Task instead of ValueTask. |