c# - 如何使用 SqlDataReader 返回和使用 IAsyncEnumerable
问题描述
请看以下两种方法。第一个返回一个IAsyncEnumerable
. 第二个试图消耗它。
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Threading;
using System.Threading.Tasks;
public static class SqlUtility
{
public static async IAsyncEnumerable<IDataRecord> GetRecordsAsync(
string connectionString, SqlParameter[] parameters, string commandText,
[EnumeratorCancellation]CancellationToken cancellationToken)
{
using (SqlConnection connection = new SqlConnection(connectionString))
{
await connection.OpenAsync(cancellationToken).ConfigureAwait(false);
using (SqlCommand command = new SqlCommand(commandText, connection))
{
command.Parameters.AddRange(parameters);
using (var reader = await command.ExecuteReaderAsync()
.ConfigureAwait(false))
{
while (await reader.ReadAsync().ConfigureAwait(false))
{
yield return reader;
}
}
}
}
}
public static async Task Example()
{
const string connectionString =
"Server=localhost;Database=[Redacted];Integrated Security=true";
SqlParameter[] parameters = new SqlParameter[]
{
new SqlParameter("VideoID", SqlDbType.Int) { Value = 1000 }
};
const string commandText = "select * from Video where VideoID=@VideoID";
IAsyncEnumerable<IDataRecord> records = GetRecordsAsync(connectionString,
parameters, commandText, CancellationToken.None);
IDataRecord firstRecord = await records.FirstAsync().ConfigureAwait(false);
object videoID = firstRecord["VideoID"]; //Should be 1000.
// Instead, I get this exception:
// "Invalid attempt to call MetaData when reader is closed."
}
}
当代码尝试读取结果IDataReader
(at object videoID = firstRecord["VideoID"];
)时,我得到了这个异常:
阅读器关闭时调用元数据的尝试无效。
这是因为SqlDataReader
被处置。有人可以提供推荐的方法来SqlDataReader
以异步方式枚举,以便调用方法可以使用每个结果记录吗?谢谢你。
解决方案
在这种情况下,LINQ 不是您的朋友,因为FirstAsync
它将在迭代器返回结果之前关闭它,这不是 ADO.NET 所期望的;基本上:不要在这里使用 LINQ,或者至少:不要以这种方式。您可能可以使用类似的东西在序列仍然打开时Select
执行投影,或者将这里的所有工作卸载到像 Dapper 这样的工具可能更容易。或者,手动进行:
await foreach (var record in records)
{
// TODO: process record
// (perhaps "break"), because you only want the first
}
推荐阅读
- django - 如何从 ListCreateAPIView 通用视图记录异常
- android - 为什么我的 Firebase 实时数据库只保存 1 个用户
- html - 图像在三星 Tizen 电视中看起来锐化且不可读
- unity3d - 应用程序终止时在控制台上返回一个值
- node.js - 使用 Travis CI 将不同的文件夹部署到不同的 Heroku 应用程序
- visual-studio-2017 - 为什么有些变量声明有“苍白”的颜色?
- android - 将文件从我的数据库下载到特定位置
- javascript - jQuery逐节向下滚动
- c++ - c ++:带有自动功能的Extern无法编译
- java - 将文本文件的内容添加到哈希集中