I'm sure I've mentioned this type of wrapper class for accessing databases in a provider-agnostic manner before, but never posted a functional implementation. So here it is. Questions, comments, and suggestions are welcome as always. :)
Simple database access wrapper class
using System;
using System.Data;
using System.Data.Common;
using System.Runtime.Serialization;
namespace JRD.Database
{
/// <summary>
/// Thrown when a data access request fails.
/// </summary>
[Serializable]
public class DataAccessException : Exception
{
/// <summary>
/// Creates a new instance.
/// </summary>
public DataAccessException() { }
/// <summary>
/// Creates a new instance initialized with the specified message string.
/// </summary>
/// <param name="message">The error message that explains the reason for the exception.</param>
public DataAccessException(string message) : base(message) { }
/// <summary>
/// Creates a new instance initialized with the specified message string and inner exception.
/// </summary>
/// <param name="message">The error message that explains the reason for the exception.</param>
/// <param name="inner">The exception that is the cause of the current exception.</param>
public DataAccessException(string message, Exception inner) : base(message, inner) { }
/// <summary>
/// Creates a new instance initialized with serialization data.
/// </summary>
/// <param name="info">The object that holds the serialized object data.</param>
/// <param name="context">The contextual information about the source or destination.</param>
protected DataAccessException(SerializationInfo info, StreamingContext context) : base(info, context) { }
}
/// <summary>
/// Represents parameter information for a command into the DataAccessManager.
/// </summary>
public class DatabaseParameter
{
/// <summary>
/// Gets or sets the SQL command parameter name of the parameter.
/// </summary>
public string Name { get; set; }
/// <summary>
/// Gets or sets the value of the parameter.
/// </summary>
public object Value { get; set; }
/// <summary>
/// Gets or sets the expected type of the parameter value.
/// </summary>
public DbType Type { get; set; }
/// <summary>
/// Creates and initializes a new instance.
/// </summary>
/// <param name="name">The name of the database parameter.</param>
/// <param name="value">The value of the parameter.</param>
/// <remarks>
/// The expected type is defaulted, which may create performance problems with implict typing in the database.
/// </remarks>
public DatabaseParameter(string name, object value)
{
Name = name;
Value = value;
}
/// <summary>
/// Creates and initializes a new instance.
/// </summary>
/// <param name="name">The name of the database parameter (eg. @MyParameter or :MyParameter)</param>
/// <param name="value">The value of the parameter.</param>
/// <param name="type">The expected type of the parameter.</param>
public DatabaseParameter(string name, object value, DbType type)
{
Name = name;
Value = value;
Type = type;
}
}
/// <summary>
/// Provides data provider agnostic queries and commands.
/// </summary>
public class DataAccessManager : IDisposable
{
#region IDisposable Implementation
public void Dispose()
{
// Does nothing; included for future using statement support.
}
#endregion
private DbProviderFactory ProviderFactory { get; set; }
/// <summary>
/// Gets or sets the external data store provider name (ex. System.Data.SqlClient).
/// </summary>
public string ProviderName { get; set; }
/// <summary>
/// Gets or sets the external data store connection string.
/// </summary>
public string ConnectionString { get; set; }
/// <summary>
/// Creates and initializes a new instance.
/// </summary>
/// <param name="providerName">The data provider name (ex. System.Data.SqlClient).</param>
/// <param name="connectionString">An appropriate connection string for the data provider.</param>
public DataAccessManager(string providerName, string connectionString)
{
ProviderName = providerName;
ConnectionString = connectionString;
ProviderFactory = DbProviderFactories.GetFactory(ProviderName);
}
#region Commands
/// <summary>
/// Selects a DataTable from the DbProvider.
/// </summary>
/// <param name="commandText">The select command text to execute.</param>
/// <param name="args">Parameter definitions for the command.</param>
/// <returns>A DataTable containing records selected from the DbProvider.</returns>
public DataTable Select(string commandText, params DatabaseParameter[] args)
{
var result = new DataTable();
try
{
using (var connection = GetConnection())
{
using (var command = ProviderFactory.CreateCommand())
{
command.Connection = connection;
command.CommandType = CommandType.Text;
command.CommandText = commandText;
foreach (var arg in args)
{
AddParameter(command, arg);
}
using (var adapter = ProviderFactory.CreateDataAdapter())
{
adapter.SelectCommand = command;
adapter.Fill(result);
}
}
}
}
catch (Exception ex)
{
throw new DataAccessException("Provider: " + ProviderName + Environment.NewLine + "CommandText: " + commandText, ex);
}
return result;
}
/// <summary>
/// Executes a non-query command on the DbProvider.
/// </summary>
/// <param name="commandText">The non-query command text to execute.</param>
/// <param name="args">Parameter definitions for the command.</param>
public void ExecuteCommand(string commandText, params DatabaseParameter[] args)
{
try
{
using (var connection = GetConnection())
{
using (var command = ProviderFactory.CreateCommand())
{
command.Connection = connection;
command.CommandType = CommandType.Text;
command.CommandText = commandText;
foreach (var arg in args)
{
AddParameter(command, arg);
}
command.ExecuteNonQuery();
}
}
}
catch (Exception ex)
{
throw new DataAccessException("Provider: " + ProviderName + Environment.NewLine + "CommandText: " + commandText, ex);
}
}
#endregion
#region Validation
/// <summary>
/// Sanitizes an identifier for the provider by quoting it.
/// </summary>
/// <param name="identifier">The identifier to sanitize.</param>
/// <returns>The sanitized identifier.</returns>
public string QuotedIdentifier(string identifier)
{
using (var builder = ProviderFactory.CreateCommandBuilder())
{
return builder.QuoteIdentifier(identifier);
}
}
/// <summary>
/// Checks a table name to verify that it exists in the DbProvider.
/// </summary>
/// <param name="tableName">Name of the table to verify.</param>
/// <param name="isQuoted">True if the table name is already quoted.</param>
/// <returns>True if the table exists, false otherwise.</returns>
public bool TableExists(string tableName, bool isQuoted)
{
using (var connection = GetConnection())
{
using (var tables = connection.GetSchema("Tables"))
{
string newTable = isQuoted ? tableName : QuotedIdentifier(tableName);
foreach (DataRow row in tables.Rows)
{
string existingTable = QuotedIdentifier(row["TABLE_NAME"].ToString());
if (existingTable == newTable)
{
return true;
}
}
return false;
}
}
}
#endregion
#region Miscellaneous Helpers
/// <summary>
/// Retrieves an open connection from the provider factory.
/// </summary>
/// <returns>An open DbConnection.</returns>
private DbConnection GetConnection()
{
var connection = ProviderFactory.CreateConnection();
connection.ConnectionString = ConnectionString;
connection.Open();
return connection;
}
/// <summary>
/// Adds the provided database parameter to the provided command.
/// </summary>
/// <param name="command">The command the parameter will be added to.</param>
/// <param name="parameter">The parameter settings.</param>
private void AddParameter(DbCommand command, DatabaseParameter parameter)
{
var p = command.CreateParameter();
p.ParameterName = parameter.Name;
p.Value = parameter.Value;
p.DbType = parameter.Type;
command.Parameters.Add(p);
}
#endregion
}
}
JOSheaIV 119 C# Addict
deceptikon 1,790 Code Sniper Team Colleague Featured Poster
JOSheaIV 119 C# Addict
Yushell 0 Newbie Poster
Be a part of the DaniWeb community
We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.