/************************************************************************************
*
* Umbraco Data Layer
* MIT Licensed work
* ©2008 Ruben Verborgh
*
***********************************************************************************/
using System;
using System.Data;
using System.Diagnostics;
using System.IO;
using System.Xml;
using umbraco.DataLayer.Utility;
namespace umbraco.DataLayer
{
///
/// Abstract base class for SQL helpers that use parameters implementing IDataParameter.
///
/// SQL parameter data type.
public abstract class SqlHelper
: ISqlHelper where P : IDataParameter
{
#region Private Fields
/// The connection string that provides access to the SQL database.
private readonly string m_ConnectionString;
#endregion
#region Protected Fields
/// Utility that provides access to complex database actions.
protected IUtilitySet m_Utility;
#endregion
#region Public Properties
///
/// Gets the connection string that provides access to the SQL database.
///
/// The connection string that provides access to the SQL database.
public string ConnectionString
{
get { return m_ConnectionString; }
}
///
/// Gets the Umbraco utility associated with this SQL helper.
///
/// The utilities.
public IUtilitySet Utility
{
get { return m_Utility; }
}
#endregion
#region Public Constructors
///
/// Initializes a new instance of the class.
///
/// The connection string.
public SqlHelper(string connectionString) : this(connectionString, null)
{ }
///
/// Initializes a new instance of the class.
///
/// The connection string, cannot be null.
/// The utility, a default utility will be used if null.
public SqlHelper(string connectionString, IUtilitySet utility)
{
// Check arguments
if (connectionString == null)
throw new ArgumentNullException("connectionString");
if (utility == null)
utility = new DefaultUtility>(this);
// Initialize member fields
m_ConnectionString = connectionString;
m_Utility = utility;
#if DEBUG && DebugDataLayer
// Log creation
Trace.TraceInformation(GetType().Name + " created.");
#endif
}
///
/// Releases unmanaged resources and performs other cleanup operations before the
/// is reclaimed by garbage collection.
///
~SqlHelper()
{
Dispose();
}
#endregion
#region Protected Methods
///
/// Performs necessary conversion on the SQL command prior to its execution.
///
/// The command text.
/// The original command text. Inheriting classes can change this behavior.
protected virtual string ConvertCommand(string commandText)
{
if (commandText == null)
throw new ArgumentNullException("commandText");
return commandText;
}
///
/// Performs necessary conversion on the parameters prior to its execution.
///
/// The parameters. Expected to be of type IParameterContainer.
/// The parameters, converted to the raw types of their containers.
protected virtual P[] ConvertParameters(IParameter[] parameters)
{
// Check arguments
if (parameters == null)
throw new ArgumentNullException("parameters");
// Add raw types of parameters to an array
P[] newParams = new P[parameters.Length];
for (int index = 0; index < parameters.Length; index++)
{
// Get raw type out of container
IParameterContainer parameter = parameters[index] as IParameterContainer
;
if (parameter == null)
throw new ArgumentException(
String.Format("Element {0} of parameters has the wrong type. Expected: IParameterContainer<{1}>. Received: {2}.",
index,
typeof(P).Name,
(parameter==null ? "null" : parameter.GetType().Name)),
"parameters");
newParams[index] = parameter.RawParameter;
}
return newParams;
}
/// Converts the scalar value to the given type.
/// Desired type of the value.
/// A scalar returned by ExecuteScalar.
/// The scalar, converted to type T.
protected virtual T ConvertScalar(object scalar)
{
if (scalar == null || (scalar == DBNull.Value && !typeof(T).IsAssignableFrom(typeof(DBNull))))
return default(T);
switch(typeof(T).FullName)
{
case "System.Int32": return (T)(object)int.Parse(scalar.ToString());
case "System.Int64": return (T)(object)long.Parse(scalar.ToString());
default: return (T)scalar;
}
}
#endregion
#region ISqlHelper Members
///
/// Escapes a string for use in an SQL query.
///
/// The value.
/// The escaped value.
/// You should use SQL parameters instead.
public virtual string EscapeString(string value)
{
return string.IsNullOrEmpty(value) ? string.Empty : value.Replace("'", "''");
}
///
/// Creates a new parameter for use with this specific implementation of ISqlHelper.
///
/// Name of the parameter.
/// Value of the parameter.
/// A new parameter of the correct type.
/// Abstract factory pattern
public abstract IParameter CreateParameter(string parameterName, object value);
///
/// Executes a command that returns a single value.
///
/// The type of the value.
/// The command text.
/// The parameters.
/// The return value of the command.
/// If a data source error occurs.
public T ExecuteScalar(string commandText, params IParameter[] parameters)
{
string commandConverted = ConvertCommand(commandText);
P[] parametersConverted = ConvertParameters(parameters);
try
{
return ConvertScalar(ExecuteScalar(commandConverted, parametersConverted));
}
catch (Exception e)
{
throw new SqlHelperException("ExecuteScalar", commandText, parameters, e);
}
}
///
/// Executes a command and returns the number of rows affected.
///
/// The command text.
/// The parameters.
///
/// The number of rows affected by the command.
///
/// If a data source error occurs.
public int ExecuteNonQuery(string commandText, params IParameter[] parameters)
{
string commandConverted = ConvertCommand(commandText);
P[] parametersConverted = ConvertParameters(parameters);
try
{
return ExecuteNonQuery(commandConverted, parametersConverted);
}
catch (Exception e)
{
throw new SqlHelperException("ExecuteNonQuery", commandText, parameters, e);
}
}
///
/// Executes a command and returns a records reader containing the results.
///
/// The command text.
/// The parameters.
///
/// A data reader containing the results of the command.
///
/// If a data source error occurs.
public IRecordsReader ExecuteReader(string commandText, params IParameter[] parameters)
{
string commandConverted = ConvertCommand(commandText);
P[] parametersConverted = ConvertParameters(parameters);
try
{
return ExecuteReader(commandConverted, parametersConverted);
}
catch (Exception e)
{
throw new SqlHelperException("ExecuteReader", commandText, parameters, e);
}
}
///
/// Executes a command that returns an XML value.
///
/// The command text.
/// The parameters.
///
/// An XML reader containing the return value.
///
/// If a data source error occurs.
public XmlReader ExecuteXmlReader(string commandText, params IParameter[] parameters)
{
string commandConverted = ConvertCommand(commandText);
P[] parametersConverted = ConvertParameters(parameters);
try
{
return ExecuteXmlReader(commandConverted, parametersConverted);
}
catch (Exception e)
{
throw new SqlHelperException("ExecuteXmlReader", commandText, parameters, e);
}
}
#endregion
#region Abstract Query Methods
///
/// Executes a command that returns a single value.
///
/// The command text.
/// The parameters.
/// The return value of the command.
protected abstract object ExecuteScalar(string commandText, P[] parameters);
///
/// Executes a command and returns the number of rows affected.
///
/// The command text.
/// The parameters.
///
/// The number of rows affected by the command.
///
protected abstract int ExecuteNonQuery(string commandText, params P[] parameters);
///
/// Executes a command and returns a records reader containing the results.
///
/// The command text.
/// The parameters.
///
/// A data reader containing the results of the command.
///
protected abstract IRecordsReader ExecuteReader(string commandText, params P[] parameters);
///
/// Executes a command that returns an XML value.
///
/// The command text.
/// The parameters.
///
/// An XML reader containing the return value.
///
protected virtual XmlReader ExecuteXmlReader(string commandText, params P[] parameters)
{
string xmlString = (string)ExecuteScalar(commandText, parameters);
if (xmlString == null)
throw new ArgumentException("The query didn't return a value.");
return XmlReader.Create(new StringReader(xmlString));
}
#endregion
#region IDisposable Members
///
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
///
public virtual void Dispose()
{ }
#endregion
}
}