我的应用程序有一个公共数据库类,在该类中我有一个函数
public MySqlDataReader getRecord(string query)
{
MySqlDataReader reader;
using (var connection = new MySqlConnection(connectionString))
{
connection.Open();
using (var cmd = new MySqlCommand(query, connection))
{
reader = cmd.ExecuteReader();
return reader;
}
}
return null;
}
在我使用的页面后面的代码
String sql = "SELECT * FROM `table`";
MySqlDataReader dr = objDB.getRecord(sql);
if (dr.Read())
{
// some code goes hear
}
我遇到错误读取器关闭时读取次数无效。
我知道在数据库连接关闭后无法访问阅读器 机器人我正在寻找一个解决方案,其中我无需改变代码隐藏
编辑:我将解决读者被分配到其他对象(类似于读者)并返回该对象的解决方案,因此我无需更改所有应用程序页面
答案 0 :(得分:9)
您可以将查询结果加载到内存中,然后关闭连接并仍然返回按预期工作的IDataReader
。请注意,这会花费内存。
public IDataReader getRecord(string query)
{
MySqlDataReader reader;
using (var connection = new MySqlConnection(connectionString))
{
connection.Open();
using (var cmd = new MySqlCommand(query, connection))
{
reader = cmd.ExecuteReader();
var dt = new DataTable();
dt.Load( reader );
return dt.CreateDataReader();
}
}
return null;
}
在来电者中:
String sql = "SELECT * FROM `table`";
var dr = objDB.getRecord(sql); // or DataTableReader dr = ...
if (dr.Read())
{
// some code goes here
}
答案 1 :(得分:5)
当您对using (var connection = new MySqlConnection(connectionString))
的通话结束时,连接将会关闭。
但是,您仍然会根据该连接返回阅读器。一旦您尝试在调用方法中使用它,您将收到错误,因为无法使用关闭连接。
此外,您的方法称为GetRecord
,但它会返回一个读者。
其中一个选项是:
public void processQuery(string query, Action<MySqlDataReader> fn)
{
using (var connection = new MySqlConnection(connectionString))
{
connection.Open();
using (var cmd = new MySqlCommand(query, connection))
{
using (var reader = cmd.ExecuteReader())
{
fn(reader);
}
}
}
}
// caller
String sql = "SELECT * FROM `table`";
objDB.procesQuery(sql, dr => {
if (dr.Read())
{
// some code goes here
}
});
您创建一个“类似于阅读器”的对象的想法,因此您不必更改调用者,将无法工作:返回的对象需要包含阅读器和打开的连接,以便您可以使用读者。这意味着您必须关闭调用者中的连接。在最好的情况下,调用者需要修改如下:
String sql = "SELECT * FROM `table`";
using (MyWrapper wr = objDB.getRecord(sql))
{
if (wr.Reader.Read())
{
// some code goes here
}
}
您不会保存那么多工作,但是由于连接泄漏,调用者中缺少using
个语句会导致您的应用在一段时间后无法正常工作。
答案 2 :(得分:0)
你想要的是什么,但它不是一个好的解决方案,因为你必须包装MySqlDataReader
类的所有功能并将其转发给真正的MySqlDataReader
。
请参阅ConnectedMySqlDataReader
类(提示:它不实现MySqlDataReader的所有功能,如果您真的想要使用它,您必须自己完成)以及它如何适合您的解决方案:
public ConnectedMySqlDataReader GetRecord(string query)
{
return new ConnectedMySqlDataReader(connectionString, query);
}
// ...
var sql = "SELECT * FROM `table`";
using(var dr = objDB.GetRecord(sql))
{
if (dr.Read())
{
// some code goes hear
}
}
我没有测试过这个课程,只是为了演示!
using System;
using System.Collections;
using System.Data;
using System.Data.Common;
using MySql.Data.MySqlClient;
namespace MySqlTest
{
public class ConnectedMySqlDataReader : DbDataReader
{
private readonly MySqlConnection _connection;
private readonly Lazy<MySqlDataReader> _reader;
private MySqlCommand _command;
public ConnectedMySqlDataReader(MySqlConnection connection, string query)
{
if(connection == null)
throw new ArgumentNullException("connection");
_connection = connection;
_reader = new Lazy<MySqlDataReader>(() =>
{
_connection.Open();
_command = new MySqlCommand(query, _connection);
return _command.ExecuteReader();
});
}
public ConnectedMySqlDataReader(string connectionString, string query)
: this(new MySqlConnection(connectionString), query) { }
private MySqlDataReader Reader
{
get { return _reader.Value; }
}
public override void Close()
{
if (_reader.IsValueCreated)
_reader.Value.Close();
if(_command != null)
_command.Dispose();
_connection.Dispose();
}
public override DataTable GetSchemaTable()
{
return this.Reader.GetSchemaTable();
}
public override bool NextResult()
{
return this.Reader.NextResult();
}
public override bool Read()
{
return this.Reader.Read();
}
public override int Depth
{
get { return this.Reader.Depth; }
}
public override bool IsClosed
{
get { return this.Reader.IsClosed; }
}
public override int RecordsAffected
{
get { return this.Reader.RecordsAffected; }
}
public override bool GetBoolean(int ordinal)
{
return this.Reader.GetBoolean(ordinal);
}
public override byte GetByte(int ordinal)
{
return this.Reader.GetByte(ordinal);
}
public override long GetBytes(int ordinal, long dataOffset, byte[] buffer, int bufferOffset, int length)
{
return this.Reader.GetBytes(ordinal, dataOffset, buffer, bufferOffset, length);
}
public override char GetChar(int ordinal)
{
return this.Reader.GetChar(ordinal);
}
public override long GetChars(int ordinal, long dataOffset, char[] buffer, int bufferOffset, int length)
{
return this.Reader.GetChars(ordinal, dataOffset, buffer, bufferOffset, length);
}
public override Guid GetGuid(int ordinal)
{
return this.Reader.GetGuid(ordinal);
}
public override short GetInt16(int ordinal)
{
return this.Reader.GetInt16(ordinal);
}
public override int GetInt32(int ordinal)
{
return this.Reader.GetInt32(ordinal);
}
public override long GetInt64(int ordinal)
{
return this.Reader.GetInt64(ordinal);
}
public override DateTime GetDateTime(int ordinal)
{
return this.Reader.GetDateTime(ordinal);
}
public override string GetString(int ordinal)
{
return this.Reader.GetString(ordinal);
}
public override object GetValue(int ordinal)
{
return this.Reader.GetValue(ordinal);
}
public override int GetValues(object[] values)
{
return this.Reader.GetValues(values);
}
public override bool IsDBNull(int ordinal)
{
return this.Reader.IsDBNull(ordinal);
}
public override int FieldCount
{
get { return this.Reader.FieldCount; }
}
public override object this[int ordinal]
{
get { return this.Reader[ordinal]; }
}
public override object this[string name]
{
get { return this.Reader[name]; }
}
public override bool HasRows
{
get { return this.Reader.HasRows; }
}
public override decimal GetDecimal(int ordinal)
{
return this.Reader.GetDecimal(ordinal);
}
public override double GetDouble(int ordinal)
{
return this.Reader.GetDouble(ordinal);
}
public override float GetFloat(int ordinal)
{
return this.Reader.GetFloat(ordinal);
}
public override string GetName(int ordinal)
{
return this.Reader.GetName(ordinal);
}
public override int GetOrdinal(string name)
{
return this.Reader.GetOrdinal(name);
}
public override string GetDataTypeName(int ordinal)
{
return this.Reader.GetDataTypeName(ordinal);
}
public override Type GetFieldType(int ordinal)
{
return this.Reader.GetFieldType(ordinal);
}
public override IEnumerator GetEnumerator()
{
return this.Reader.GetEnumerator();
}
}
}
PS:这是sealed in c# context的含义,是的,MySqlDataReader
是sealed
。