我在.NET Core 2.0应用程序中有以下功能。
public DataTable CallDb(string connStr, string sql)
{
var dt = new DataTable();
var da = new SqlDataAdapter(sql, connStr);
da.Fill(dt);
return dt;
}
如何将其转换为异步函数?
public async Task<DataTable> CallDb(string connStr, string sql)
{
var dt = new DataTable();
var da = new SqlDataAdapter(sql, connStr);
da.Fill(dt); // No FillAsync to await?
return dt;
}
我需要使用DataTable
因为sql可能会返回不同架构的数据。有没有更好的方法来处理动态模式?
答案 0 :(得分:5)
SqlDataAdapter
从未更新为包含方法的TPL版本。你可以这样做:
await Task.Run(() => da.Fill(dt));
但那会创建一个无用的线程。
一个好的方法是使用这样的东西:
public async Task<DataTable> CallDb(string connStr, string sql)
{
var dt = new DataTable();
var connection = new SqlConnection(connStr);
var reader = await connection.CreateCommand().ExecuteReaderAsync();
dt.Load(reader);
return dt;
}
当然,应该进行一些更改,例如using
语句。但是,在这里,您正在以正确的方式使用异步调用。
答案 1 :(得分:1)
尽管在这种情况下不会阻塞对ExecuteReaderAsync()
的初始调用,但是dt.Load(reader)
可能等效于reader.Read()
而不是await reader.ReadAsync()
,并且可能在检索行。
如果您确实需要DataTable
来与外部API配合使用,或者因为您事先不知道字段定义,但是需要完全异步的行为,那么最好使用自己的代码来构造一个DataTable
,添加所需的列,例如基于reader.GetName()
和reader.GetFieldType()
,然后使用await reader.ReadAsync()
和dt.Rows.Add()
在循环中填充行。