当我尝试返回元组时,IDataReader关闭

时间:2020-07-11 10:49:38

标签: c# idatareader

我正在尝试返回一个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

2 个答案:

答案 0 :(得分:3)

您看到的是使用IEnumerabledeferred execution的效果,在这种情况下,是从IEnumerable<T>方法返回的Select

您将返回一个IEnumerable<CustomerViewModel>作为元组的一部分,目前尚未执行。然后,通过使用using来处理连接和读取器。

当方法返回后您随后尝试迭代IEnumerable<CustomerViewModel>时,捕获的数据读取器已经作为处理的一部分被关闭。

通过调试器进行检查时,Results是一种遍历可枚举的方法,此时数据读取器尚未被处理。

防止这种情况的一种选择是在返回之前先在ToList上调用results


这与javascript中的生成器类似。

答案 1 :(得分:1)

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