Можно ли вернуть объект OleDbDataReader из метода? - PullRequest
2 голосов
/ 08 мая 2020

Можно ли вернуть объект OleDb.OleDbDataReader из функции?

Если да, то как бы вы go это сделали?

Мой текущий код возвращает объект чтения данных, но когда я пытаюсь прочитать этот объект, я получаю сообщение об ошибке: System.InvalidOperationException: 'Invalid attempt to call Read when reader is closed.'

Мой код:

 OleDbDataReader queryData = sendQueryReturnData("SELECT * FROM users WHERE username = ?;", Parameters);
 while (queryData.Read()) //error on this line
 {
     //stuff
 }

Ответы [ 2 ]

1 голос
/ 09 мая 2020

Один из способов сохранить queryData в области видимости - сделать его полем типа IDisposable и не позволять никаким другим методам закрывать его, например:

using System;
using System.Data.OleDb;

namespace TwitterSeachTest
{
    public class MyDataClass : IDisposable
    {
        OleDbDataReader queryData;
        OleDbCommand command;
        OleDbConnection conn;

        public object[] Parameters { get; set; } = new object[0];

        public void DoReadData()
        {
            sendQueryReturnData("SELECT * FROM users WHERE username = ?;", Parameters);
            while (queryData.Read()) //error on this line
            {
                //stuff
            }
        }

        private void sendQueryReturnData(string queryString, object parameters)
        {
            this.conn = new OleDbConnection("connectionstring");
            this.command = new OleDbCommand(queryString, conn);
            conn.Open();

            this.queryData = command.ExecuteReader();

            // your code
        }

        #region IDisposable Support
        private bool disposedValue = false; // To detect redundant calls

        protected virtual void Dispose(bool disposing)
        {
            if (!disposedValue)
            {
                if (disposing)
                {
                    this.queryData?.Close();
                    this.command?.Dispose();
                    this.conn?.Close();
                }

                // TODO: free unmanaged resources (unmanaged objects) and override a finalizer below.
                // TODO: set large fields to null.

                disposedValue = true;
            }
        }

        // TODO: override a finalizer only if Dispose(bool disposing) above has code to free unmanaged resources.
        // ~MyDataClass()
        // {
        //   // Do not change this code. Put cleanup code in Dispose(bool disposing) above.
        //   Dispose(false);
        // }

        // This code added to correctly implement the disposable pattern.
        public void Dispose()
        {
            // Do not change this code. Put cleanup code in Dispose(bool disposing) above.
            Dispose(true);
            // TODO: uncomment the following line if the finalizer is overridden above.
            // GC.SuppressFinalize(this);
        }
        #endregion
    }
}

Я положил ваш код в DoReadData, а разница в том, что queryData теперь является полем, а не локальной переменной.

Я также добавил пример кода для sendQueryReturnData. Обратите внимание, что он присваивает результаты command.ExecuteReader полю queryData. Не используйте здесь using.

Наконец, реализуйте шаблон удаления с помощью IDispose. Следствием этого является то, что тот, кто использует этот класс, должен теперь использовать оператор using или вызывать Dispose.

Тем не менее, обычно проще просто прочитать данные из базы данных и закрыть / удалить БД. объекты, как только вы закончите. Вместо этого создайте DTO, который представляет данные, заполнит и вернет List<MyDataDto>, а затем закройте / удалите ресурсы. Это уменьшает двусмысленность в отношении того, когда и кто несет ответственность за высвобождение этих ресурсов.

0 голосов
/ 09 мая 2020

Похоже, вы пытаетесь "обернуть" вызов функции ... Итак, у вас есть центральное место для получения дескриптора соединения, передачи запроса и отправки считывающего устройства, чтобы вы могли обработать его там. Как прокомментировали другие, все закрытие, удаление, очистка и т. Д. c ... Что вы могли бы сделать, так это создать дополнительный параметр для вашей функции, который принимает Action, ожидающий чтения данных. Вы читаете то, что хотите, и возвращаете, а затем закрываете то, что вам нужно. Ниже приведен только ОБРАЗЕЦ для реализации.

Опять же, не идеально, но принципы .. Централизованный класс получит соединение, открытие, закрытие, освобождение. Подготовьте команду запроса, которую вы уже создали, а затем передайте ее обратно и позвольте методу Action фактически обрабатывать чтение, поскольку разные запросы будут иметь свою собственную структуру / столбцы возврата, et c. это то, что, как я ДУМАЮ, вы пытаетесь завершить.

Вы все равно захотите, чтобы ваш try / catch, например, отсутствие действующего соединения open / close, добавил ваши вызовы dispose, но принцип может быть тем, что вы ищете.

    public class MyQueryWrapper
    {
        public GetMyData(OleDbCommand cmd, Action<OleDbDataReader> letYouReadIt)
        {
            using (var conn = new OleDbConnection(yourConnectionString))
            {
                conn.Open();
                cmd.Connection = conn;
                using (var rdr = cmd.ExecuteReader())
                {
                    // Now, call YOUR routine with the reader object while
                    // it is still active...
                    letYouReadIt(rdr);
                }
                conn.Close();
            }
        }
    }


    public class YourOtherClass
    {
        public void GetUser()
        {
            var mqr = new MyQueryWrapper();
            var sqlcmd = new OleDbCommand();
            // prepare the command and parameters.
            myUsers = new List<someUsers>();
            mqr.GetMyData(sqlcmd, ReadRecordsHere);
        }

        private List<someUsers> myUsers;

        public void ReadRecordsHere(OleDbReader rdr)
        {
            while (rdr.Read())
            {
                // read record, add to the "myUsers" list
                // keep reading until all records, then get out
            }
        }
    }
...