是否可以从方法中返回OleDbDataReader对象?

问题描述 投票:0回答:2

是否可以从函数中返回OleDb.OleDbDataReader对象?

如果是这样,您将如何去做?

我当前的代码返回了数据读取器对象,但是当我尝试读取该对象时,我得到一个错误,提示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
 }
c# oledb oledbdatareader
2个回答
0
投票

保持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

也就是说,通常,从数据库中读取数据并在完成后立即关闭/处置DB对象会更容易。而是创建一个表示数据的DTO,填充并返回List<MyDataDto>,然后关闭/处置资源。这减少了何时以及由谁负责释放这些资源的歧义。


0
投票

听起来好像您正在尝试“包装”函数调用...所以您有一个中心位置来获取连接句柄,传递查询并让阅读器发回以便可以在那里进行处理。正如其他人所评论的那样,整个关闭,处置,清理等……您可以做的是为函数创建一个附加参数,该参数接受需要数据读取器的Action。您阅读了想要的内容并返回,然后关闭了所需的内容。下面只是一个示例。

再次,不是完美的,而是原则。。集中式的类将获得连接,打开,关闭,释放。准备已经建立的查询命令,然后传回并让Action方法实际处理读数,因为不同的查询将具有自己的返回结构/列等,这就是我想总结的内容。

您仍然希望尝试/捕获,例如没有有效的打开/关闭连接,添加您的处置调用,但原理可能是您要寻找的。

    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
            }
        }
    }
© www.soinside.com 2019 - 2024. All rights reserved.