是否可以从函数中返回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
}
保持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>
,然后关闭/处置资源。这减少了何时以及由谁负责释放这些资源的歧义。
听起来好像您正在尝试“包装”函数调用...所以您有一个中心位置来获取连接句柄,传递查询并让阅读器发回以便可以在那里进行处理。正如其他人所评论的那样,整个关闭,处置,清理等……您可以做的是为函数创建一个附加参数,该参数接受需要数据读取器的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
}
}
}