C# 异步填充数据表?

C# 异步填充数据表?,c#,.net-core,C#,.net Core,我在.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(str

我在.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;
}
公共异步任务CallDb(字符串connStr,字符串sql)
{
var dt=新数据表();
var da=新的SqlDataAdapter(sql,connStr);
da.Fill(dt);//没有要等待的FillAsync吗?
返回dt;
}

我需要使用
DataTable
,因为sql可能返回具有不同模式的数据。有没有更好的方法来处理动态模式?

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;
}
公共异步任务CallDb(字符串connStr,字符串sql)
{
var dt=新数据表();
var connection=新的SqlConnection(connStr);
var reader=wait connection.CreateCommand().ExecuteReaderAsync();
dt.负载(读卡器);
返回dt;
}

当然,应该进行一些更改,例如使用语句进行
。但是,这里您使用异步调用的方式是正确的。

尽管在这种情况下对
ExecuteReaderAsync()
的初始调用不会阻塞,
dt.Load(reader)
可能与
reader.Read()
等效,而不是
wait reader.ReadAsync()
,并可能在检索行时阻止调用线程


如果您确实需要一个
DataTable
用于外部API,或者因为您事先不知道字段定义,但需要完全异步的行为,您最好使用自己的代码来构造
DataTable
,添加所需的列,例如基于
reader.GetName()
reader.GetFieldType()
,然后使用
wait reader.ReadAsync()
dt.rows.Add()

在循环中用行填充它,不知道你为什么要用它来标记它?这是一个使用EF core 2.0的.Net core应用程序,我在这个问题中根本看不到它的使用,这使它变得无关紧要。但是你打算如何使用这种方法呢?您可以使用EF Core实现这一点,具体取决于所需内容的复杂性。此代码存在根本性缺陷。这将迫使您使用非常不安全的方法来构建sql字符串,使您的程序极易受到sql注入攻击。您需要为该方法定义一个额外的参数,以允许它接受SqlParameter数据。参数还有助于避免诸如名为
O'Brien
的人员之类的原始数据问题,并有助于提高性能。第二,这种态度确实会在其他项目中导致糟糕的代码。参数就是正确的方法。学会正确地使用它们,并在您的公共数据模式中考虑它们,这样当只是为了好玩的代码突然变成现实时,您就已经在以正确的方式做事情了。虽然这个答案通过在方法中使用另一个wait来解决问题,但当大量IO发生在dt.Load中时,它不会释放线程。这就是使用异步的最大好处所在。@SaebAmini-但它肯定是在SQL Server处理查询时以及在开始返回结果之前释放线程吗?因此有一些好处,这可能非常重要。@Joe true,当您释放线程的往返时间+SQL server实际处理查询所需的时间时,会有一些好处。如果您有很高的延迟/一个需要花费大量时间处理的复杂查询,那么这一部分可能非常重要。但我想指出的是,大多数IO通常发生在您实际从读取器检索结果时,这仍然在
dt.Load
中同步执行。为了获得这一好处,您应该使用由
SqlDataReader
NextResultAsync
ReadAsync
提供的异步方法,或者创建自己的
dt.LoadAsync
。github在向DataAdapters API添加异步功能方面存在问题。