【问题标题】:IDataReader is closed when I try to return a tuple当我尝试返回元组时,IDataReader 已关闭
【发布时间】:2020-07-11 10:49:38
【问题描述】:

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

【问题讨论】:

标签: c# idatareader


【解决方案1】:

您看到的是使用IEnumerabledeferred execution 的效果,在本例中,是从您的Select 方法返回的IEnumerable&lt;T&gt;

您将返回一个 IEnumerable&lt;CustomerViewModel&gt; 作为元组的一部分,此时尚未执行。然后通过using的使用来处理连接和阅读器。

当您随后在方法返回后尝试迭代 IEnumerable&lt;CustomerViewModel&gt; 时,捕获的数据读取器已作为处置的一部分关闭。

当您通过调试器进行检查时,Results 是一种迭代可枚举的方法,此时尚未释放数据读取器。

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


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

【讨论】:

    【解决方案2】:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-07-18
      • 1970-01-01
      • 2014-09-15
      • 1970-01-01
      • 2021-07-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多