使用异步 ADO.NET 调用填充数据集会抛出 InvalidOperationException
Filling a DataSet using asynchronous ADO.NET calls throws InvalidOperationException
我希望能够使用 .NET 4.5+ 异步 ADO.NET 方法,用可能 return 多个结果集的查询结果填充数据集。我正在使用的代码如下。当我 运行 代码时,我看到前两个 table 已成功填充 - 以下内容输出到控制台:
Table Table1 loaded with 1 row(s)
Table Table2 loaded with 1 row(s)
然后在第三个table被填充之前,我得到一个System.InvalidOperationException : Invalid attempt to call NextResultAsync when reader is closed
。
我不明白这一点,因为 reader 位于调用 NextResultAsync 的循环之外。
我使用的是 Visual Studio 2017,LocalDB @@VERSION 是 "Microsoft SQL Server 2016 (SP1) (KB3182545) - 13.0.4001.0 ..."(在连接字符串中不使用 Asynchronous Processing
关键字)。
在我看来 reader 被 DataTable.Load
关闭了 - 但为什么呢?为什么在第二个循环而不是第一个?
谁能告诉我我做错了什么?
[Test]
public void RunTestQuery()
{
const string QueryText = @"
DECLARE @Table1 TABLE (Col1 VARCHAR(50))
DECLARE @Table2 TABLE (Col1 VARCHAR(50))
DECLARE @Table3 TABLE (Col1 VARCHAR(50))
INSERT INTO @Table1 VALUES ('T1Value')
INSERT INTO @Table2 VALUES ('T2Value')
INSERT INTO @Table3 VALUES ('T3Value')
SELECT * FROM @Table1
SELECT * FROM @Table2
SELECT * FROM @Table3
";
var dataSet = GetDataSet(QueryText).Result;
Assert.AreEqual(3, dataSet.Tables.Count);
}
private async Task<DataSet> GetDataSet(string commandText)
{
DataSet dataSet = new DataSet();
using (var connection = new System.Data.SqlClient.SqlConnection())
{
connection.ConnectionString = @"Server=(LocalDB)\MSSQLLocalDB;Trusted_Connection=True";
await connection.OpenAsync();
using (DbCommand command = connection.CreateCommand())
{
command.CommandText = commandText;
using (var reader = await command.ExecuteReaderAsync())
{
do
{
var table = dataSet.Tables.Add();
table.Load(reader);
Console.WriteLine($"Table {table.TableName} loaded with {table.Rows.Count} row(s)");
} while (await reader.NextResultAsync());
}
}
return dataSet;
}
}
我看过 DataTable.Load
方法,有问题的代码是:
...
loadAdapter.FillFromReader(new DataTable[]
{
this
}, reader, 0, 0);
if (!reader.IsClosed && !reader.NextResult())
{
reader.Close();
}
...
即DataTable.Load
在内部调用 reader.NextResult
,因此不能在调用 reader.NextResult[Async]
.
的循环中使用
所以我必须编写自定义方法来填充 DataTable
,这可能是更好的解决方案,因为 DataTable.Load
不使用异步方法。
我希望能够使用 .NET 4.5+ 异步 ADO.NET 方法,用可能 return 多个结果集的查询结果填充数据集。我正在使用的代码如下。当我 运行 代码时,我看到前两个 table 已成功填充 - 以下内容输出到控制台:
Table Table1 loaded with 1 row(s)
Table Table2 loaded with 1 row(s)
然后在第三个table被填充之前,我得到一个System.InvalidOperationException : Invalid attempt to call NextResultAsync when reader is closed
。
我不明白这一点,因为 reader 位于调用 NextResultAsync 的循环之外。
我使用的是 Visual Studio 2017,LocalDB @@VERSION 是 "Microsoft SQL Server 2016 (SP1) (KB3182545) - 13.0.4001.0 ..."(在连接字符串中不使用 Asynchronous Processing
关键字)。
在我看来 reader 被 DataTable.Load
关闭了 - 但为什么呢?为什么在第二个循环而不是第一个?
谁能告诉我我做错了什么?
[Test]
public void RunTestQuery()
{
const string QueryText = @"
DECLARE @Table1 TABLE (Col1 VARCHAR(50))
DECLARE @Table2 TABLE (Col1 VARCHAR(50))
DECLARE @Table3 TABLE (Col1 VARCHAR(50))
INSERT INTO @Table1 VALUES ('T1Value')
INSERT INTO @Table2 VALUES ('T2Value')
INSERT INTO @Table3 VALUES ('T3Value')
SELECT * FROM @Table1
SELECT * FROM @Table2
SELECT * FROM @Table3
";
var dataSet = GetDataSet(QueryText).Result;
Assert.AreEqual(3, dataSet.Tables.Count);
}
private async Task<DataSet> GetDataSet(string commandText)
{
DataSet dataSet = new DataSet();
using (var connection = new System.Data.SqlClient.SqlConnection())
{
connection.ConnectionString = @"Server=(LocalDB)\MSSQLLocalDB;Trusted_Connection=True";
await connection.OpenAsync();
using (DbCommand command = connection.CreateCommand())
{
command.CommandText = commandText;
using (var reader = await command.ExecuteReaderAsync())
{
do
{
var table = dataSet.Tables.Add();
table.Load(reader);
Console.WriteLine($"Table {table.TableName} loaded with {table.Rows.Count} row(s)");
} while (await reader.NextResultAsync());
}
}
return dataSet;
}
}
我看过 DataTable.Load
方法,有问题的代码是:
...
loadAdapter.FillFromReader(new DataTable[]
{
this
}, reader, 0, 0);
if (!reader.IsClosed && !reader.NextResult())
{
reader.Close();
}
...
即DataTable.Load
在内部调用 reader.NextResult
,因此不能在调用 reader.NextResult[Async]
.
所以我必须编写自定义方法来填充 DataTable
,这可能是更好的解决方案,因为 DataTable.Load
不使用异步方法。