2012-01-31 132 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