当我尝试返回元组时,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())上得到了错误。

有人能告诉我如何解决我的问题吗?


我在这里列出了以下例子:

如何轻松地将DataReader转换为List<T>?

将数据读取器中的行转换为键入的结果


EDIT-我正在使用dotnetcore

您看到的是使用IEnumerable时延迟执行的效果,在本例中,是从Select方法返回的IEnumerable<T>

您将返回一个IEnumerable<CustomerViewModel>作为元组的一部分,该元组目前尚未执行。然后连接&正在通过使用CCD_ 12来布置读取器。

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

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

防止这种情况发生的一种选择是在返回之前在results上呼叫ToList


这是一个类似于javascript中生成器的概念。

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

最新更新