The ExecuteReaderAsync
of the OdbcCommand
class most probably has the default synchronous implementation provided by the DbCommand
base class. This means that also the await reader.ReadAsync()
is most probably 100% synchronous. You could fix this problem by offloading the synchronous call to a background thread, using the Task.Run
method:
var reader = await Task.Run(() => cmd.ExecuteReader());
while (await Task.Run(() => reader.Read()))
{
The dgv.Invoke(new Action(
is probably redundant, because the QueryDataAsync
is called from the UI thread.
Mixing data retrieval code with UI manipulation code is probably not a good idea, because it results to tight coupling between the application layers. If you are using C# 8 or later you could consider exposing the data in the form of an asynchronous stream (IAsyncEnumerable<string>
):
internal async IAsyncEnumerable<string> QueryDataAsync()
{
//...
con.Open();
var reader = await Task.Run(() => cmd.ExecuteReader());
while (await Task.Run(() => reader.Read()))
{
yield return reader.GetString(0);
}
//...
}
...and consume it from the presentation layer like this:
private async void LoadData(object sender, EventArgs e)
{
await foreach (string value in presenter.QueryDataAsync())
{
dgv.Rows.Add(value);
}
}
It would still be tricky because of the compile error:
Error CS1626 Cannot yield a value in the body of a try block with a catch clause
You would probably have to replace the catch
with a finally
, and have the consumer handle the errors.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…