/************************************************************************************ * * Umbraco Data Layer * MIT Licensed work * ©2008 Ruben Verborgh * ***********************************************************************************/ using System; using System.Data; using System.Collections; using System.Collections.Generic; using System.Diagnostics; namespace umbraco.DataLayer { /// /// Class that adapts a generic data reader to an IRecordsReader. /// /// The data reader class public abstract class RecordsReaderAdapter : IRecordsReader where D : IDataReader, IDataRecord, IEnumerable { #region Private Fields /// Wrapped data reader. private readonly D m_DataReader; /* Use the DebugDataLayer compile constant to get information about the opened RecordsReaderAdapters. */ #if DEBUG && DebugDataLayer /// Application unique identifier of this RecordsReaderAdapter. /// Used to track different instantiations for debug purposes. private readonly int m_Id; /// Application unique identifier that will be assigned to the next new RecordsReaderAdapter. /// Used to track different instantiations for debug purposes. private static int m_GlobalId = 0; /// List of identifiers of open RecordsReaderAdapters. /// Used to track different instantiations for debug purposes. private static List m_OpenDataReaderIds = new List(); #endif #endregion #region Public Properties /// Gets the internal data reader. /// The data reader. public D DataReader { get { return m_DataReader; } } /// Gets the internal data reader. /// The data reader. /// Obsolete. You should NOT try to close or dispose the RawDataReader, /// but instead close or dispose this RecordsReaderAdapter. /// Inheriting classes can call the protected DataReader property. [Obsolete("Only for backwards compatibility.", false)] public D RawDataReader { get { return m_DataReader; } } #endregion #region Constructors and destructors /// /// Initializes a new instance of the class. /// /// The data reader. public RecordsReaderAdapter(D dataReader) { m_DataReader = dataReader; #if DEBUG && DebugDataLayer lock (m_OpenDataReaderIds) { // Get application unique identifier m_Id = m_GlobalId++; // Signal the creation of this new RecordsReaderAdapter m_OpenDataReaderIds.Add(m_Id); StackFrame stackFrame = new StackFrame(4); string caller = stackFrame.GetMethod().ReflectedType.Name + "." + stackFrame.GetMethod().Name; Trace.TraceInformation(m_Id + ". RecordsReader created by " + caller + ". " + "Open Data Readers: " + m_OpenDataReaderIds.Count); } #endif } /// /// Releases unmanaged resources and performs other cleanup operations before the /// is reclaimed by garbage collection. /// ~RecordsReaderAdapter() { Dispose(false); } #endregion #region IRecordsReader Members /// /// Closes the data reader. /// public virtual void Close() { try { m_DataReader.Close(); } catch { } #if DEBUG && DebugDataLayer // Log closing lock (m_OpenDataReaderIds) { m_OpenDataReaderIds.Remove(m_Id); Trace.TraceInformation(m_Id + ". RecordsReader closed. " + "Open Data Readers: " + m_OpenDataReaderIds.Count); } #endif } /// /// Gets the depth of nesting of the current row. /// /// The depth of nesting of the current row. public int Depth { get { return m_DataReader.Depth; } } /// /// Gets a value indicating whether this instance is closed. /// /// true if this instance is closed; otherwise, false. public bool IsClosed { get { return m_DataReader.IsClosed; } } /// /// Advances to the next record. /// /// /// true if there are more records; otherwise, false. /// public bool Read() { return m_DataReader.Read(); } /// /// Gets a value indicating whether this instance has records. /// /// /// true if this instance has records; otherwise, false. /// public abstract bool HasRecords { get; } /// /// Gets the value of the specified field. /// /// The field type. /// Name of the field. /// The value of the specified field public FieldType Get(string fieldName) { switch (typeof(FieldType).FullName) { case "System.Boolean": return (FieldType)(object)GetBoolean(fieldName); case "System.Byte": return (FieldType)(object)GetByte(fieldName); case "System.DateTime": return (FieldType)(object)GetDateTime(fieldName); case "System.Decimal": return (FieldType)(object)GetDecimal(fieldName); case "System.Double": return (FieldType)(object)GetDouble(fieldName); case "System.Single": return (FieldType)(object)GetFloat(fieldName); case "System.Guid": return (FieldType)(object)GetGuid(fieldName); case "System.Int16": return (FieldType)(object)GetShort(fieldName); case "System.Int32": return (FieldType)(object)GetInt(fieldName); case "System.Int64": return (FieldType)(object)GetLong(fieldName); case "System.String": return (FieldType)(object)GetString(fieldName); default: return (FieldType)GetObject(fieldName); } } /// /// Gets the value of the specified field as a bool. /// /// Name of the field. /// The value of the field. /// No column with the specified name was found. public bool GetBoolean(string fieldName) { return m_DataReader.GetBoolean(GetOrdinal(fieldName)); } /// /// Gets the value of the specified field as a byte. /// /// Name of the field. /// The value of the field. /// No column with the specified name was found. public byte GetByte(string fieldName) { return m_DataReader.GetByte(GetOrdinal(fieldName)); } /// /// Gets the value of the specified field as a DateTime. /// /// Name of the field. /// The value of the field. /// No column with the specified name was found. public DateTime GetDateTime(string fieldName) { return m_DataReader.GetDateTime(GetOrdinal(fieldName)); } /// /// Gets the value of the specified field as a decimal. /// /// Name of the field. /// The value of the field. /// No column with the specified name was found. public decimal GetDecimal(string fieldName) { return m_DataReader.GetDecimal(GetOrdinal(fieldName)); } /// /// Gets the value of the specified field as a double. /// /// Name of the field. /// The value of the field. /// No column with the specified name was found. public double GetDouble(string fieldName) { return m_DataReader.GetDouble(GetOrdinal(fieldName)); } /// /// Gets the value of the specified field as a float. /// /// Name of the field. /// The value of the field. /// No column with the specified name was found. public float GetFloat(string fieldName) { return m_DataReader.GetFloat(GetOrdinal(fieldName)); } /// /// Gets the value of the specified field as a Guid. /// /// Name of the field. /// The value of the field. /// No column with the specified name was found. public Guid GetGuid(string fieldName) { return m_DataReader.GetGuid(GetOrdinal(fieldName)); } /// /// Gets the value of the specified field as a short. /// /// Name of the field. /// The value of the field. /// No column with the specified name was found. public short GetShort(string fieldName) { return m_DataReader.GetInt16(GetOrdinal(fieldName)); } /// /// Gets the value of the specified field as an int. /// /// Name of the field. /// The value of the field. /// No column with the specified name was found. public int GetInt(string fieldName) { int ordinal = GetOrdinal(fieldName); return m_DataReader.IsDBNull(ordinal) ? -1 : m_DataReader.GetInt32(ordinal); } /// /// Gets the value of the specified field as a long. /// /// Name of the field. /// The value of the field. /// No column with the specified name was found. public long GetLong(string fieldName) { return m_DataReader.GetInt64(GetOrdinal(fieldName)); } /// /// Gets the value of the specified field as a string. /// /// Name of the field. /// The value of the field. /// No column with the specified name was found. public string GetString(string fieldName) { int ordinal = GetOrdinal(fieldName); return m_DataReader.IsDBNull(ordinal) ? null : m_DataReader.GetString(ordinal); } /// /// Gets the value of the specified field. /// /// Name of the field. /// The value of the field. /// No column with the specified name was found. public object GetObject(string fieldName) { int ordinal = GetOrdinal(fieldName); return m_DataReader.IsDBNull(ordinal) ? null : m_DataReader.GetValue(ordinal); } /// /// Determines whether the specified field is null. /// /// Name of the field. /// /// true if the specified field is null; otherwise, false. /// public bool IsNull(string fieldName) { return m_DataReader.IsDBNull(GetOrdinal(fieldName)); } /// /// Determines whether a field with the specified field name exists in the record. /// The field can still contain a null value. /// /// Name of the field. /// /// true if the specified field exists; otherwise, false. /// public bool ContainsField(string fieldName) { bool fieldExists; try { GetOrdinal(fieldName); fieldExists = true; } catch { // GetOrdinal failed, field was not found. fieldExists = false; } return fieldExists; } /// /// Returns the index of the field with the specified name. /// /// The name of the field. /// The index of the field. protected virtual int GetOrdinal(string fieldName) { return m_DataReader.GetOrdinal(fieldName); } #endregion #region IEnumerable Members /// /// Returns an enumerator that iterates through the records. /// /// /// An object that can be used to iterate through records. /// public IEnumerator GetEnumerator() { return m_DataReader.GetEnumerator(); } #endregion #region IDisposable Members /// /// Performs application-defined tasks associated with freeing, releasing, /// or resetting unmanaged resources. /// public void Dispose() { Dispose(true); } /// /// Releases unmanaged and - optionally - managed resources. /// /// true to release both managed and unmanaged resources; /// false to release only unmanaged resources. protected virtual void Dispose(bool disposing) { // Try to close the data reader if it's still open try { if (m_DataReader != null && !m_DataReader.IsClosed) Close(); } finally { // Try to dispose the data reader try { if (m_DataReader != null) m_DataReader.Dispose(); } catch { } // Dispose methods should call SuppressFinalize if (disposing) { GC.SuppressFinalize(this); } } } #endregion } }