2012-01-31 3 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); 
     } 
    } 
} 

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

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

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

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

+0

Не используйте 'throw ex'', он теряет полезную информацию из исключения. Вместо этого используйте «throw». – svick

+0

Вы уверены, что '_dataReader' является' null', а не каким-то другим объектом? – svick

+0

svick - я уверен. –

ответ

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.QueryInterrupted или MySqlErrorCode. FileSortAborted. И пока выясняется, что это какая-то проблема с сервером, поскольку, по крайней мере, в моем случае проблема несовместима и выглядит как многопоточная проблема в коде сервера.

-1

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

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

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

+0

Сборщик мусора никогда не располагает объектами. Он завершает объекты, если они недостижимы, но это не приведет к нулевому полю. И если объект недоступен, значит, по определению вы не можете его достичь. – svick

+0

Это ** MySqlDataReader **, а не SqlDataReader ... Я могу получить доступ к ManagedDataReader, я не могу получить доступ к _dataReader, потому что он каким-то образом установлен в null. спасибо в любом случае ... –

+0

Любые идеи? это по-прежнему актуально для меня ... –