是否可以从方法中 return OleDbDataReader 对象?
Is it possible to return an OleDbDataReader object from a method?
是否可以从函数中 return OleDb.OleDbDataReader 对象?
如果是,你会怎么做?
我当前的代码 return 是数据 reader 对象,但是当我尝试读取该对象时,我收到一条错误消息 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
实现处置模式。这样做的结果是使用此 class 的人现在必须使用 using
语句或调用 Dispose
.
也就是说,通常在完成后立即从数据库和 close/dispose 数据库对象中读取数据会更容易。相反,创建一个代表数据的 DTO,填充和 return 一个 List<MyDataDto>
然后 close/dispose 资源。这减少了何时以及由谁负责释放这些资源的模糊性。
听起来你正在尝试 "wrap" 函数调用...所以你有一个中心位置来获取连接句柄,传递查询并发回 reader 这样你可以在那里处理。正如其他人评论的那样,整个关闭、处理、清理等......你可以做的是为你的函数创建一个额外的参数,它接受一个 Action
期望数据 reader。你读你想读的 return,然后关闭你需要的。下面只是一个要实现的示例。
同样,不完美,但原则.. 集中式 class 将获得连接、打开、关闭、释放。准备您已经建立的查询命令,然后传回并让 Action 方法实际处理读取,因为不同的查询将有自己的 return structure/columns,等等,这就是我认为您正在尝试的包起来。
你仍然想要你的 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
}
}
}
是否可以从函数中 return OleDb.OleDbDataReader 对象?
如果是,你会怎么做?
我当前的代码 return 是数据 reader 对象,但是当我尝试读取该对象时,我收到一条错误消息 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
实现处置模式。这样做的结果是使用此 class 的人现在必须使用 using
语句或调用 Dispose
.
也就是说,通常在完成后立即从数据库和 close/dispose 数据库对象中读取数据会更容易。相反,创建一个代表数据的 DTO,填充和 return 一个 List<MyDataDto>
然后 close/dispose 资源。这减少了何时以及由谁负责释放这些资源的模糊性。
听起来你正在尝试 "wrap" 函数调用...所以你有一个中心位置来获取连接句柄,传递查询并发回 reader 这样你可以在那里处理。正如其他人评论的那样,整个关闭、处理、清理等......你可以做的是为你的函数创建一个额外的参数,它接受一个 Action
期望数据 reader。你读你想读的 return,然后关闭你需要的。下面只是一个要实现的示例。
同样,不完美,但原则.. 集中式 class 将获得连接、打开、关闭、释放。准备您已经建立的查询命令,然后传回并让 Action 方法实际处理读取,因为不同的查询将有自己的 return structure/columns,等等,这就是我认为您正在尝试的包起来。
你仍然想要你的 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
}
}
}