Почему мой объект MysqlDataReader становится нулевым? - PullRequest
1 голос
/ 31 января 2012

У меня есть следующий класс:

using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics;
using MySql.Data.MySqlClient;

namespace DataBaseModule.General
{
    public class ManagedDataReader : IDisposable
    {

        private bool _disposed = false;
        private MySqlCommand _command;

        private MySqlDataReader _dataReader;
        // The class constructor.
        public ManagedDataReader(string StrSQL)
            : this(new MySqlCommand(StrSQL))
        {
        }

        public ManagedDataReader(MySqlCommand SQL_Cmd)
        {
            try
            {
                _command = SQL_Cmd;
                _command.Connection = new MySqlConnection(DbAccessProvider._connectionString);
                DbAccessProvider.SqlCommandsPerformed++;
                _command.Connection.Open();
                _dataReader = _command.ExecuteReader();
            }
            catch (Exception ex)
            {
                DataBaseModule.Log.CommonLogger.Log_Database_Error(new Exception("Sql command Was: " + _command.CommandText, ex));
                throw ex;
            }
        }

        public int VisibleFieldCount()
        {
            return _dataReader.VisibleFieldCount;
        }

        public bool Read()
        {
            return _dataReader.Read();
        }

        public object this[int i]
        {
            get
            {
                if (_dataReader[i].Equals(DBNull.Value))
                {
                    return null;
                }
                else
                {
                    return _dataReader[i];
                }
            }
        }

        public object this[string FieldName]
        {
            get
            {
                if (_dataReader[FieldName].Equals(DBNull.Value))
                {
                    return null;
                }
                else
                {
                    return _dataReader[FieldName];
                }
            }
        }

        // Implement IDisposable.
        // Do not make this method virtual.
        // A derived class should not be able to override this method.
        public void Dispose()
        {
            Dispose(true);
            // This object will be cleaned up by the Dispose method.
            // Therefore, you should call GC.SupressFinalize to
            // take this object off the finalization queue 
            // and prevent finalization code for this object
            // from executing a second time.
            GC.SuppressFinalize(this);
        }

        // Dispose(bool disposing) executes in two distinct scenarios.
        // If disposing equals true, the method has been called directly
        // or indirectly by a user's code. Managed and unmanaged resources
        // can be disposed.
        // If disposing equals false, the method has been called by the 
        // runtime from inside the finalizer and you should not reference 
        // other objects. Only unmanaged resources can be disposed.
        protected void Dispose(bool disposing)
        {
            // Check to see if Dispose has already been called.
            if (!this._disposed)
            {
                // If disposing equals true, dispose all managed 
                // and unmanaged resources.
                if (disposing)
                {
                    if (_dataReader != null)
                    {
                        _dataReader.Close();
                    }
                    if (_command != null)
                    {
                        if (_command.Connection != null)
                        {
                            _command.Connection.Dispose();
                            _command.Connection = null;
                            //Free the reference.
                        }
                        _command.Dispose();
                    }
                }
                // Call the appropriate methods to clean up 
                // unmanaged resources here.
                // If disposing is false, 
                // only the following code is executed.
                // Note disposing has been done.
                _disposed = true;
            }
        }

        // This finalizer will run only if the Dispose method 
        // does not get called.
        // It gives your base class the opportunity to finalize.
        // Do not provide finalize methods in types derived from this class.
        ~ManagedDataReader()
        {
            // Do not re-create Dispose clean-up code here.
            // Calling Dispose(false) is optimal in terms of
            // readability and maintainability.
            Dispose(false);
        }
    }
}

Моя проблема в том, что по какой-то причине иногда я получаю исключение при вызове Read (): Исключением является то, что мой член _dataReader имеет значение null.

Это странно, потому что у меня есть блок try-catch при его инициализации, и никакое исключение не перехватывается (я использую свой механизм регистрации для проверки этого).

Такое поведение встречается редко, но встречается приблизительно. один раз в неделю (я выполняю миллионы запросов в день)

Большое спасибо всем, кто пытается разгадать эту тайну !!

Ответы [ 2 ]

2 голосов
/ 11 января 2013

Я придумал ту же проблему. И оказалось, что в некоторых случаях ExecuteReader () действительно может возвращать ноль.

Я посмотрел код разъема, и вот что я нашел:

catch (MySqlException ex)
{

...

// if we caught an exception because of a cancel, then just return null
if (ex.IsQueryAborted)
    return null;

Копать немного глубже получается IsQueryAborted истинно, когда сервер возвращает MySqlErrorCode.QueryInterrupted или MySqlErrorCode.FileSortAborted . И до сих пор выясняется, что это какая-то проблема с сервером, поскольку, по крайней мере, в моем случае эта проблема не является согласованной и выглядит как проблема многопоточности в коде сервера.

0 голосов
/ 31 января 2012

Я просмотрел код и нашел, что единственный способ получить с NULL-ридером - это исключение из кода инициализации.

Поскольку SqlDataReader.ExecuteReader возвращает объект во всех случаях и не может его вернутьноль.Татьяна Рачева подтвердила, что при отражении класса SqlDataReader в этот ответ .

Второй сценарий для использования NULL-чтения - это если вы пытаетесь использовать ридер после того, как объект ManagedDataReader удаляется мусоромколлектор.

...