任务完毕时,连接正在关闭
本文关键字:连接 任务 | 更新日期: 2023-09-27 18:08:33
我试图使用Task.WhenAll执行多个sqldatareader。但是当等待任务时,我得到
"系统。InvalidOperationException:无效操作。连接
关闭"。
创建任务:
List<Task<SqlDataReader>> _listTasksDataReader = new List<Task<SqlDataReader>>();
_listTasksDataReader.Add(GetSqlDataReader1(10));
_listTasksDataReader.Add(GetSqlDataReader2(10));
SqlDataReader[] _dataReaders = await Task.WhenAll(_listTasksDataReader);
我的"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();
}
}
}
不应该打开数据库连接时,任务。WhenAll被执行,还是我错过了什么?
可以传递CommandBehavior。CloseConnection to ExecuteReaderAsync。然后连接将保持打开状态,直到返回的数据读取器对象被关闭:参见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);
}
}
我错过了什么吗?
你想要得到一个没有底层连接的SqlDataReader
?我觉得这样不行。当你从读者那里读的时候会发生什么?连接已关闭。
因此,您可能只需要在关闭连接之前读取实际数据:
public async Task<List<T>> GetData1(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;
var result = new List<T>();
var reader = await command.ExecuteReaderAsync();
// TODO: use `reader` to populate `result`
return result;
}
}
}
更新:我要把这个留在这里,但我刚刚记得你不允许将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;
}
}
}
注意,这个模式有一个"陷阱"。每个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};
}
}
}