4

アプリケーションに共通のデータベースクラスがあり、そのクラスに関数があります

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
} 

リーダーが閉じているときに無効な読み取り試行としてエラーが発生します。

データベース接続が閉じられた後にリーダーにアクセスすることは不可能であることを知っていますボット私はコードビハインドで変更する必要がない回避策を探しています

編集:リーダーが他のオブジェクト(リーダーと同様)に割り当てられているソリューションが好きで、そのオブジェクトを返すので、すべてのアプリケーションページで変更する必要はありません

4

3 に答える 3

11

クエリの結果をメモリにロードしてから、接続を閉じても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
} 
于 2012-10-02T12:00:44.870 に答える
5

呼び出しのスコープがusing (var connection = new MySqlConnection(connectionString)) 終了すると、接続が閉じられます。

ただし、その接続に基づいてリーダーを返すことになります。呼び出し元のメソッドで使用しようとすると、閉じた接続を使用できないため、エラーが発生します。

その上、あなたのメソッドは呼び出されGetRecordますが、それはリーダーを返します。

オプションの1つは、これを行うことです。

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、呼び出し元に1つのステートメントがない場合、接続リークが原因でしばらくするとアプリが機能しなくなります。

于 2012-10-02T11:10:58.983 に答える
0

MySqlDataReader必要なことは可能ですが、クラスのすべての関数をラップして実際のに転送する必要があるため、これは良い解決策ではありませんMySqlDataReader。クラス(ヒント: MySqlDataReaderConnectedMySqlDataReaderのすべての関数を実装しているわけではありません。本当に使用したい場合は、自分で実行する必要があります)と、ソリューションにどのように適合するかを確認してください。

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:これはc#コンテキストで封印されていることを意味し、そうMySqlDataReaderですsealed

于 2012-10-02T11:58:28.183 に答える