1

我有以下课程:

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 成员为空。

这很奇怪,因为我在初始化时有 try-catch 块,并且没有捕获到异常(我使用我的日志机制来检查这一点)。

这种行为很少见,但发生在 aprox。每周一次(我每天运行数百万个查询)

非常感谢任何试图解决这个谜团的人!!

4

2 回答 2

2

我想出了同样的问题。事实证明,ExecuteReader() 在某些情况下实际上可以返回 null。

我查找了连接器的代码,这就是我发现的:

catch (MySqlException ex)
{

...

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

当服务器返回MySqlErrorCode.QueryInterruptedMySqlErrorCode.FileSortAborted时,再深入一点发现IsQueryAborted为真。到目前为止,事实证明这是一些服务器问题,因为至少在我的情况下,问题并不一致,看起来像是服务器代码中的多线程问题。

于 2013-01-11T14:19:59.907 回答
-1

我查看了代码,发现使用 NULL 阅读器的唯一方法是在初始化代码中出现异常。

由于 SqlDataReader.ExecuteReader 在所有情况下都返回一个对象并且不能返回 null。Tatiana Racheva 通过反射 SqlDataReader 类在这个答案中确认了这一点。

拥有 NULL 读取器的第二种情况是,如果您在垃圾收集器处理 ManagedDataReader 对象后尝试使用读取器。

于 2012-01-31T09:26:38.160 回答