/************************************************************************************
*
* 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
}
}