当我尝试 return 元组时 IDataReader 关闭

IDataReader is closed when I try to return a tuple

我正在尝试 return 一个由我从数据库中选择的记录数组组成的 HTTP 响应。但是我无法将 IDataReader 映射到 Enumerable。这是我的相关代码部分:

namespace Web.Api.Controllers
{
    public static class Blah
    {
        public static IEnumerable<T> Select<T>(this IDataReader reader,
                                       Func<IDataReader, T> projection)
        {
            while (reader.Read())
            {
                yield return projection(reader);
            }
        }
    }
    
    [HttpPost]
    [Route("Search")]
    public async Task<Tuple<int, IEnumerable<CustomerViewModel>, int>> Search([FromBody]CustomerViewModel model)
    {
        var s = _configuration.GetConnectionString("DefaultConnectionAlt");
        

        using (SqlConnection connection = new SqlConnection(s))
        {

            connection.Open();

            using (SqlCommand command = new SqlCommand("Search @RegistrationDate=\"2020-07-09\"", connection))
            {
                using (IDataReader reader = command.ExecuteReader())
                {
                    var results = reader.Select<CustomerViewModel>(CustomerViewModel.Create);
                    return Tuple.Create(0, results, 29);
                }
            }
        }

    }
}

当我向 http://localhost:42432/api/Search 发送 POST 请求时,行 while (reader.Read()) 给出了错误:

System.InvalidOperationException: 'Invalid attempt to call Read when reader is closed.'

我在 return Tuple.Create(0, results, 29); 处设置了一个断点,当我检查 results 变量时,它显示了我期望的结果。但是在我走出那个断点之后,我在 while (reader.Read()).

上得到了错误

谁能告诉我如何解决我的问题?


我正在按照此处列出的示例进行操作:

How can I easily convert DataReader to List<T>?

Convert rows from a data reader into typed results


编辑 - 我正在使用 dotnetcore

您看到的是使用 IEnumerabledeferred execution 的效果,在本例中,IEnumerable<T> 从您的 [=12] 中 return =]方法。

您正在 returning 一个 IEnumerable<CustomerViewModel> 作为元组的一部分,此时尚未执行。然后通过使用 using.

处理连接 & reader

当您随后尝试在该方法 return 编辑后迭代 IEnumerable<CustomerViewModel> 时,捕获的数据 reader 已作为处置的一部分关闭。

当你通过调试器检查时,Results是一个遍历可枚举的方法,此时数据reader还没有被释放。

防止这种情况的一个选择是在 return.

之前在 results 上调用 ToList

这与 javascript 中的生成器概念相似。

请记住,IEnumerable 是按需延迟处理的。 在您的特定情况下, Search returns 元组值与 IEnumerable 尚未读取。 因此 reader 在填充 IEnumerable 之前被关闭。