IDataReader закрывается, когда я пытаюсь вернуть кортеж - PullRequest
1 голос
/ 11 июля 2020

Я пытаюсь вернуть 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);
                }
            }
        }

    }
}

Когда я отправляю запрос POST на http://localhost:42432/api/Search, строка 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 в список ?

Преобразовать строки из считывателя данных в набранные результаты

EDIT - я использую dotnetcore

Ответы [ 2 ]

3 голосов
/ 11 июля 2020

То, что вы видите, - это эффект отложенного выполнения при использовании IEnumerable, в данном случае IEnumerable<T>, который возвращается вашим Select методом.

Вы возвращаете IEnumerable<CustomerViewModel> как часть кортежа, который на данный момент еще не был выполнен. Затем соединение и считыватель удаляются с использованием using.

Когда вы впоследствии пытаетесь повторить IEnumerable<CustomerViewModel> после возврата метода, считыватель захваченных данных уже был закрыт как часть dispose.

Когда вы проверяете через отладчик, Results - это метод, который выполняет итерацию по перечисляемому, и на данный момент средство чтения данных еще не удалено.

Один из вариантов предотвращения это означало бы позвонить по номеру ToList на ваш results, прежде чем вернуться.

Это аналогично генераторам в javascript.

1 голос
/ 11 июля 2020

Помните, что IEnumerable обрабатываются лениво, по запросу. В вашем конкретном случае Search возвращает значение кортежа с IEnumerable, которое еще не прочитано. Поэтому reader закрывается до заполнения IEnumerable.

...