当我尝试 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
您看到的是使用 IEnumerable
时 deferred 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
之前被关闭。
我正在尝试 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
您看到的是使用 IEnumerable
时 deferred execution 的效果,在本例中,IEnumerable<T>
从您的 [=12] 中 return =]方法。
您正在 returning 一个 IEnumerable<CustomerViewModel>
作为元组的一部分,此时尚未执行。然后通过使用 using
.
当您随后尝试在该方法 return 编辑后迭代 IEnumerable<CustomerViewModel>
时,捕获的数据 reader 已作为处置的一部分关闭。
当你通过调试器检查时,Results
是一个遍历可枚举的方法,此时数据reader还没有被释放。
防止这种情况的一个选择是在 return.
之前在results
上调用 ToList
这与 javascript 中的生成器概念相似。
请记住,IEnumerable
是按需延迟处理的。
在您的特定情况下, Search
returns 元组值与 IEnumerable
尚未读取。
因此 reader
在填充 IEnumerable
之前被关闭。