全部任务,连接正在关闭

Asu*_*sT9 6 c# sqldatareader async-await

我正在尝试使用Task.WhenAll执行多个SqlDataReaders.但是等待任务的时候,我得到了

"System.InvalidOperationException:无效操作.连接已关闭".

创建任务:

        List<Task<SqlDataReader>> _listTasksDataReader = new List<Task<SqlDataReader>>();
        _listTasksDataReader.Add(GetSqlDataReader1(10));
        _listTasksDataReader.Add(GetSqlDataReader2(10));
        SqlDataReader[] _dataReaders = await Task.WhenAll(_listTasksDataReader);
Run Code Online (Sandbox Code Playgroud)

我的"SqlDataReader"方法:

    public Task<SqlDataReader> GetSqlDataReader1(int recordCount)
    {
        using (var sqlCon = new SqlConnection(ConnectionString))
        {
            sqlCon.Open();
            using (var command = new SqlCommand("sp_GetData", sqlCon))
            {
                command.Parameters.Clear();
                command.Parameters.Add(new SqlParameter("@recordCount", recordCount));
                command.CommandType = System.Data.CommandType.StoredProcedure;
                return command.ExecuteReaderAsync();
            }
        }
    }
Run Code Online (Sandbox Code Playgroud)

执行Task.WhenAll时我不应该打开数据库连接,还是我错过了什么?

Fri*_*its 6

可以将CommandBehavior.CloseConnection传递给ExecuteReaderAsync.然后连接将保持打开状态,直到返回的datareader对象关闭:请参阅此处此处的 MSDN .在这种情况下,SqlConnection不需要在using语句中.

像这样:

public Task<SqlDataReader> GetSqlDataReader1(int recordCount)
{
    var sqlCon = new SqlConnection(ConnectionString);
    sqlCon.Open();

    using (var command = new SqlCommand("sp_GetData", sqlCon))
    {
        command.Parameters.Clear();
        command.Parameters.Add(new SqlParameter("@recordCount", recordCount));
        command.CommandType = System.Data.CommandType.StoredProcedure;
        return command.ExecuteReaderAsync(CommandBehavior.CloseConnection);
    }
}
Run Code Online (Sandbox Code Playgroud)


Joe*_*orn 2

更新:我要把这个留在这里,但我刚刚想起你不被允许合并yield……await至少现在还不行。


请记住command.ExecuteReaderAsync(),即使使用return关键字调用,也不会停止该方法的执行。这就是方法的全部要点_Async()。因此,在该函数调用之后,代码立即退出该using块。这会导致在您有机会使用连接对象从 DataReader 中读取数据之前就将其处理掉。

尝试返回一个Task<IEnumerable<IDataRecord>>

public async Task<IEnumerable<IDataRecord>> GetSqlDataReader1(int recordCount)
{
    using (var sqlCon = new SqlConnection(ConnectionString))
    using (var command = new SqlCommand("sp_GetData", sqlCon))
    {
        command.Parameters.Add("@recordCount", SqlDbType.Int).Value = recordCount;
        command.CommandType = System.Data.CommandType.StoredProcedure;

        sqlCon.Open();               
        var rdr = await command.ExecuteReaderAsync();
        while (rdr.Read())
        {
             yield return rdr;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

请注意,此模式有一个“陷阱”。每个都yield return使用相同的对象,因此如果您不小心,可能会发生一些奇怪的事情。我建议进一步更改此包含代码,将对象中每个记录的数据rdr放入它自己的(强类型)对象实例中:

public async Task<IEnumerable<SomeObject>> GetSqlDataReader1(int recordCount)
{
    using (var sqlCon = new SqlConnection(ConnectionString))
    using (var command = new SqlCommand("sp_GetData", sqlCon))
    {
        command.Parameters.Add(new SqlParameter("@recordCount", recordCount));
        command.CommandType = System.Data.CommandType.StoredProcedure;

        sqlCon.Open();                
        var rdr = await command.ExecuteReaderAsync();
        while (rdr.Read())
        {
             yield return new SomeObject() {Field1 = rdr[1], Field2 = rdr[2], etc};
        }
    }
}
Run Code Online (Sandbox Code Playgroud)