任务完成后,连接正在关闭
Task when all, connection is closing
我正在尝试使用 Task.WhenAll 执行多个 SqlDataReader。但是当等待任务时我得到
"System.InvalidOperationException: Invalid operation. The connection
is closed".
创建任务:
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();
}
}
}
执行 Task.WhenAll 时不应该打开数据库连接还是我遗漏了什么?
更新: 我打算把它留在这里,但我记得你不能合并 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;
}
}
}
请注意,此模式有一个 "gotcha"。每个 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};
}
}
}
可以将 CommandBehavior.CloseConnection 传递给 ExecuteReaderAsync。然后连接将保持打开状态,直到返回的数据读取器对象关闭:参见 MSDN here and here。在这种情况下,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);
}
}
am I missing something?
您正在尝试获取没有基础连接的 SqlDataReader
?我认为这不会奏效。当您阅读 reader 时会发生什么?连接已经关闭。
因此,您可能只需要在关闭连接之前读取实际数据即可:
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;
}
}
}
我正在尝试使用 Task.WhenAll 执行多个 SqlDataReader。但是当等待任务时我得到
"System.InvalidOperationException: Invalid operation. The connection is closed".
创建任务:
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();
}
}
}
执行 Task.WhenAll 时不应该打开数据库连接还是我遗漏了什么?
更新: 我打算把它留在这里,但我记得你不能合并 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;
}
}
}
请注意,此模式有一个 "gotcha"。每个 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};
}
}
}
可以将 CommandBehavior.CloseConnection 传递给 ExecuteReaderAsync。然后连接将保持打开状态,直到返回的数据读取器对象关闭:参见 MSDN here and here。在这种情况下,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);
}
}
am I missing something?
您正在尝试获取没有基础连接的 SqlDataReader
?我认为这不会奏效。当您阅读 reader 时会发生什么?连接已经关闭。
因此,您可能只需要在关闭连接之前读取实际数据即可:
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;
}
}
}