c# - 如何使用 SqlDataReader 返回和使用 IAsyncEnumerable

标签 c# .net async-await 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(在 object videoID = firstRecord["VideoID"];)时,我得到这个异常:

Invalid attempt to call MetaData when reader is closed.

这是因为 SqlDataReader 被释放了。有人可以提供推荐的方法以异步方式枚举 SqlDataReader 以便每个结果记录都可用于调用方法吗?谢谢。

最佳答案

在这种情况下,LINQ 不是你的 friend ,因为 FirstAsync 将在迭代器 返回结果之前关闭迭代器,这不是 ADO.NET 所期望的;基本上:不要在这里使用 LINQ,或者至少:不要以这种方式使用。您可以使用 Select 之类的东西在序列仍然打开时执行投影,或者将此处的所有工作卸载到类似的工具可能更容易小巧玲珑。或者,手动执行:

await foreach (var record in records)
{
    // TODO: process record
    // (perhaps "break"), because you only want the first
}

关于c# - 如何使用 SqlDataReader 返回和使用 IAsyncEnumerable,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58825715/

相关文章:

c# - 从 SHA1 迁移到 SHA2 ASP.net 4.5,C#

javascript - 使用 async/await Promise 在 "parallel"中运行 for 循环

c# - 为什么我不能直接访问属性 ".SingleAsync().Property"?

c# - "This file came from another computer and might be blocked to protect this computer."- 如何以编程方式在 C# .net 中删除此属性?

c# - .NET 双重除法无效强制转换异常

c# - SOAP 客户端没有完成它的工作或者可能没有返回任何东西?

c# - ComboBox - 自动完成 + 自由打字

c# - Bloomberg .Net API - 多种证券的响应数据

c# - 无法插入到我的数据库表中

c# - 使用 asp.net c# 在 Reportviewer 中设置文本框值