2012-01-31 131 views
1

我有以下类:为什么我的MysqlDataReader对象变为空?

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); 
     } 
    } 
} 

我的问题是,由于某种原因,有时我打电话时阅读了异常(): 的例外是,我_dataReader成员为空。

这很奇怪,因为我有try-catch块的初始化,并没有发现异常(我使用我的登录机制来检查)。

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

非常感谢任何试图解决这个难题的人!

+0

不要使用'throw ex;',它会从例外中丢失有用的信息。改用'throw;'代替。 – svick 2012-01-31 09:44:23

+0

你确定它是'_dataReader'是'null'而不是其他一些对象吗? – svick 2012-01-31 09:45:19

+0

svick - 我确定。 – 2012-01-31 11:45:57

回答

2

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

我抬起头连接器的代码,这是我发现:

catch (MySqlException ex) 
{ 

... 

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

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

-1

我回顾了代码,我发现获取NULL读取器的唯一方法是在初始化代码中出现异常。

由于SqlDataReader.ExecuteReader在所有情况下都返回一个对象,并且不能返回null。塔蒂亚娜Racheva已确认通过反射SqlDataReader类在this answer

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

+0

垃圾收集器从不处理对象。如果对象无法访问,它会终止对象,但不会将该字段设置为null。如果一个对象无法访问,那就意味着你无法达到它。 – svick 2012-01-31 09:42:12

+0

这是** MySqlDataReader **,而不是SqlDataReader ... 我可以访问ManagedDataReader,我无法访问_dataReader,因为它以某种方式设置为null。 无论如何感谢... – 2012-01-31 11:41:59

+0

任何想法?它仍然与我有关...... – 2012-04-02 20:14:59