using System;
using System.Collections;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Diagnostics;
using BLToolkit.Configuration;
namespace BLToolkit.Data
{
using DataProvider;
using Properties;
public partial class DbManager
{
#region Constructors
///
/// Initializes a new instance of the class
/// and opens a database connection.
///
///
///
/// This constructor uses a configuration, which has been used first in your application.
/// If there has been no connection used before, an empty string is applied as a default configuration.
///
///
/// See the property
/// for an explanation and use of the default configuration.
///
///
///
///
/// An instance of the database manager class.
[DebuggerStepThrough]
public DbManager() : this(DefaultConfiguration)
{
}
///
/// Initializes a new instance of the class
/// and opens a database connection for the provided configuration.
///
///
/// See the property
/// for an explanation and use of the configuration string.
///
///
/// Configuration string.
/// An instance of the class.
[DebuggerStepThrough]
public DbManager(string configurationString)
: this(
GetDataProvider (configurationString),
GetConnectionString(configurationString))
{
_configurationString = configurationString;
}
///
/// Initializes a new instance of the class
/// and opens a database connection for the provided configuration.
///
///
/// See the property
/// for an explanation and use of the configuration string.
///
/// Configuration string not containing provider name.
/// Provider configuration name.
/// An instance of the class.
[DebuggerStepThrough]
public DbManager(string providerName, string configuration)
: this(
GetDataProvider (providerName + ProviderNameDivider + configuration),
GetConnectionString(providerName + ProviderNameDivider + configuration))
{
_configurationString = providerName + ProviderNameDivider + configuration;
}
///
/// Initializes a new instance of the class for the provided connection.
///
///
/// This constructor tries to open the connection if the connection state equals
/// ConnectionState.Closed.
/// In this case the property of the connection
/// must be set before colling the constructor.
/// Otherwise, it neither opens nor closes the connection.
///
///
/// Type of the connection could not be recognized.
///
///
/// An instance of the class.
/// An instance of the class.
[DebuggerStepThrough]
public DbManager(IDbConnection connection)
: this(GetDataProvider(connection), connection)
{
}
///
/// Initializes a new instance of the class for the provided transaction.
///
///
///
[DebuggerStepThrough]
public DbManager(IDbTransaction transaction)
: this(GetDataProvider(transaction.Connection), transaction)
{
}
/*
///
/// Initializes a new instance of the class
/// and opens a database connection for the provided configuration and database connection.
///
///
///
/// This constructor opens the connection only if the connection state equals
/// ConnectionState.Closed.
/// Otherwise, it neither opens nor closes the connection.
///
///
/// See the property
/// for an explanation and use of the configuration string.
///
///
///
/// An instance of the .
/// The configuration string.
/// An instance of the class.
[DebuggerStepThrough]
public DbManager(
IDbConnection connection,
string configurationString)
{
if (connection == null)
{
Init(configurationString);
if (configurationString != null)
OpenConnection(configurationString);
}
else
{
Init(connection);
_configurationString = configurationString;
_connection.ConnectionString = GetConnectionString(configurationString);
if (_connection.State == ConnectionState.Closed)
OpenConnection();
}
}
*/
#endregion
#region Public Properties
private string _configurationString;
///
/// Gets the string used to open a database.
///
///
/// A string containing configuration settings.
///
///
///
/// An actual database connection string is read from the appSettings section
/// of application configuration file (App.config, Web.config, or Machine.config)
/// according to the follow rule:
///
///
/// <appSettings>
/// <add
/// key = "ConnectionString.configurationString"
/// value = "Server=(local);Database=Northwind;Integrated Security=SSPI" />
/// </appSettings>
///
///
/// If the configuration string is empty, the following rule is applied:
///
///
/// <appSettings>
/// <add
/// key = "ConnectionString"
/// value = "Server=(local);Database=Northwind;Integrated Security=SSPI" />
/// </appSettings>
///
///
/// If you don't want to use a configuration file, you can add a database connection string
/// using the method.
///
///
/// The configuration string may have a prefix used to define a data provider. The following table
/// contains prefixes for all supported data providers:
///
/// PrefixProvider
/// - SqlData Provider for SQL Server
/// - OleDbData Provider for OLE DB
/// - OdbcData Provider for ODBC
/// - OracleData Provider for Oracle
///
///
///
///
public string ConfigurationString
{
[DebuggerStepThrough]
get { return _configurationString; }
}
#endregion
#region Config Overrides
protected virtual void InitDataProvider(IDbConnection connection)
{
DataProvider = GetDataProvider(connection);
}
protected virtual IDbConnection CloneConnection()
{
if (Connection is ICloneable || ConfigurationString == null)
return _dataProvider.CloneConnection(_connection);
IDbConnection con = DataProvider.CreateConnectionObject();
con.ConnectionString = GetConnectionString(ConfigurationString);
return con;
}
protected virtual string GetConnectionHash()
{
return ConfigurationString ?? Connection.ConnectionString.GetHashCode().ToString();
}
#endregion
#region Protected Static Members
static DbManager()
{
AddDataProvider(new SqlDataProvider());
AddDataProvider(new AccessDataProvider());
AddDataProvider(new OleDbDataProvider());
AddDataProvider(new OdbcDataProvider());
BLToolkitSection section = BLToolkitSection.Instance;
if (section != null)
{
_defaultConfiguration = section.DefaultConfiguration;
foreach (DataProviderElement provider in section.DataProviders)
{
Type dataProviderType = Type.GetType(provider.TypeName, true);
DataProviderBase providerInstance = (DataProviderBase)Activator.CreateInstance(dataProviderType);
if (!string.IsNullOrEmpty(provider.Name))
providerInstance.UniqueName = provider.Name;
providerInstance.Configure(provider.Attributes);
AddDataProvider(providerInstance);
if (!provider.Default)
continue;
if (_defaultDataProviderName != null)
{
throw new ConfigurationErrorsException(string.Format(
Resources.DbManager_MoreThenOneDefaultProvider, _defaultDataProviderName, providerInstance.UniqueName),
provider.ElementInformation.Source, provider.ElementInformation.LineNumber);
}
_defaultDataProviderName = providerInstance.UniqueName;
}
}
string dataProviders = ConfigurationManager.AppSettings.Get("BLToolkit.DataProviders");
if (dataProviders != null)
{
Debug.WriteLineIf(TraceSwitch.TraceWarning, "Using appSettings\\BLToolkit.DataProviders is obsolete. Consider using bltoolkit configuration section instead.", TraceSwitch.DisplayName);
foreach (string dataProviderTypeName in dataProviders.Split(';'))
AddDataProvider(Type.GetType(dataProviderTypeName, true));
}
if (string.IsNullOrEmpty(_defaultConfiguration))
_defaultConfiguration = ConfigurationManager.AppSettings.Get("BLToolkit.DefaultConfiguration");
if (string.IsNullOrEmpty(_defaultDataProviderName))
_defaultDataProviderName = SqlDataProvider.NameString;
}
private static string _firstConfiguration;
private static DataProviderBase _firstProvider;
private static readonly Hashtable _configurationList = Hashtable.Synchronized(new Hashtable());
private static readonly Hashtable _anyProviderConfigurationList = Hashtable.Synchronized(new Hashtable());
private static DataProviderBase GetDataProvider(IDbConnection connection)
{
if (connection == null) throw new ArgumentNullException("connection");
DataProviderBase dp = _dataProviderTypeList[connection.GetType()];
if (dp == null)
throw new DataException(string.Format(
Resources.DbManager_UnknownConnectionType, connection.GetType().FullName));
return dp;
}
public static DataProviderBase GetDataProvider(string configurationString)
{
if (configurationString == null) throw new ArgumentNullException("configurationString");
if (configurationString.StartsWith(AnyProvider))
return FindFirstSuitableProvider(configurationString);
if (configurationString == _firstConfiguration)
return _firstProvider;
DataProviderBase dp = (DataProviderBase)_configurationList[configurationString];
if (dp == null)
{
ConnectionStringSettings css = ConfigurationManager.ConnectionStrings[configurationString];
if (css != null && !string.IsNullOrEmpty(css.ProviderName))
{
dp = _dataProviderNameList[css.ProviderName];
}
else
{
// configurationString can be:
// '' : default provider, default configuration;
// '.' : default provider, default configuration;
// 'foo.bar' : 'foo' provider, 'bar' configuration;
// 'foo.' : 'foo' provider, default configuration;
// 'foo' : default provider, 'foo' configuration or
// foo provider, default configuration;
// '.foo' : default provider, 'foo' configuration;
// '.foo.bar': default provider, 'foo.bar' configuration;
//
// Default provider is SqlDataProvider
//
string cs = configurationString.ToUpper();
string key = _defaultDataProviderName;
if (cs.Length > 0)
{
cs += ProviderNameDivider;
foreach (string k in _dataProviderNameList.Keys)
{
if (cs.StartsWith(k + ProviderNameDivider))
{
key = k;
break;
}
}
}
dp = _dataProviderNameList[key];
}
if (dp == null)
throw new DataException(string.Format(
Resources.DbManager_UnknownDataProvider, configurationString));
_configurationList[configurationString] = dp;
}
if (_firstConfiguration == null)
{
lock (_configurationList.SyncRoot)
{
if (_firstConfiguration == null)
{
_firstConfiguration = configurationString;
_firstProvider = dp;
}
}
}
return dp;
}
private static bool IsMatchedConfigurationString(string configurationString, string csWithoutProvider)
{
int dividerPos;
return
!configurationString.StartsWith(AnyProvider) &&
(dividerPos = configurationString.IndexOf(ProviderNameDivider)) >= 0 &&
0 == StringComparer.OrdinalIgnoreCase.Compare
(configurationString.Substring(dividerPos + ProviderNameDivider.Length), csWithoutProvider);
}
private static DataProviderBase FindFirstSuitableProvider(string configurationString)
{
string cs = (string)_anyProviderConfigurationList[configurationString];
bool searchRequired = (cs == null);
if (searchRequired)
{
string csWithoutProvider = configurationString.Substring(AnyProvider.Length);
if (configurationString.Length == 0) throw new ArgumentNullException("configurationString");
foreach (string str in _connectionStringList.Keys)
{
if (IsMatchedConfigurationString(str, csWithoutProvider))
{
cs = str;
break;
}
}
if (cs == null)
{
foreach (ConnectionStringSettings css in ConfigurationManager.ConnectionStrings)
{
if (IsMatchedConfigurationString(css.Name, csWithoutProvider))
{
cs = css.Name;
break;
}
}
}
if (cs == null)
{
foreach (string name in ConfigurationManager.AppSettings.AllKeys)
{
if (name.StartsWith("ConnectionString" + ProviderNameDivider))
{
string str = name.Substring(name.IndexOf(ProviderNameDivider) + ProviderNameDivider.Length);
if (IsMatchedConfigurationString(str, csWithoutProvider))
{
cs = str;
break;
}
}
}
}
if (cs == null)
cs = csWithoutProvider;
}
DataProviderBase dp = GetDataProvider(cs);
if (searchRequired)
_anyProviderConfigurationList[configurationString] = cs;
return dp;
}
private static readonly Dictionary
_connectionStringList = new Dictionary(4);
public static string GetConnectionString(string configurationString)
{
// Use default configuration.
//
if (configurationString == null)
configurationString = DefaultConfiguration;
if (_anyProviderConfigurationList.Contains(configurationString))
configurationString = (string)_anyProviderConfigurationList[configurationString];
string str;
// Check cached strings first.
//
if (!_connectionStringList.TryGetValue(configurationString, out str))
{
lock (_dataProviderListLock)
{
// Connection string is not in the cache.
//
string key = string.Format("ConnectionString{0}{1}",
configurationString.Length == 0? String.Empty: ProviderNameDivider, configurationString);
ConnectionStringSettings css = ConfigurationManager.ConnectionStrings[configurationString];
str = css != null? css.ConnectionString: ConfigurationManager.AppSettings.Get(key);
if (string.IsNullOrEmpty(str))
{
throw new DataException(string.Format(
Resources.DbManager_UnknownConfiguration, key));
}
// Store the result in cache.
//
_connectionStringList[configurationString] = str;
}
}
return str;
}
/*
private void OpenConnection(string configurationString)
{
// If connection is already opened, we close it and open again.
//
if (_connection != null)
{
Dispose();
GC.ReRegisterForFinalize(this);
}
// Store the configuration string.
//
_configurationString = configurationString;
// Create and open the connection object.
//
_connection = _dataProvider.CreateConnectionObject();
_connection.ConnectionString = GetConnectionString(ConfigurationString);
OpenConnection();
}
*/
#endregion
#region AddDataProvider
private static readonly Dictionary _dataProviderNameList =
new Dictionary(8, StringComparer.OrdinalIgnoreCase);
private static readonly Dictionary _dataProviderTypeList =
new Dictionary(4);
private static readonly object _dataProviderListLock = new object();
///
/// Adds a new data provider.
///
///
/// The method can be used to register a new data provider for further use.
///
///
///
///
/// An instance of the interface.
public static void AddDataProvider(DataProviderBase dataProvider)
{
if (null == dataProvider)
throw new ArgumentNullException("dataProvider");
if (string.IsNullOrEmpty(dataProvider.UniqueName))
throw new ArgumentException(Resources.DbManager_InvalidDataProviderName, "dataProvider");
if (string.IsNullOrEmpty(dataProvider.ProviderName))
throw new ArgumentException(Resources.DbManager_InvalidDataProviderProviderName, "dataProvider");
if (dataProvider.ConnectionType == null || !typeof(IDbConnection).IsAssignableFrom(dataProvider.ConnectionType))
throw new ArgumentException(Resources.DbManager_InvalidDataProviderConnectionType, "dataProvider");
lock (_dataProviderListLock)
{
_dataProviderNameList[dataProvider.UniqueName.ToUpper()] = dataProvider;
_dataProviderNameList[dataProvider.ProviderName] = dataProvider;
_dataProviderTypeList[dataProvider.ConnectionType] = dataProvider;
}
}
///
/// Adds a new data provider witch a specified name.
///
///
/// The method can be used to register a new data provider for further use.
///
///
///
///
/// The data provider name.
/// An instance of the interface.
public static void AddDataProvider(string providerName, DataProviderBase dataProvider)
{
if (dataProvider == null)
throw new ArgumentNullException("dataProvider");
if (string.IsNullOrEmpty(providerName))
throw new ArgumentException(Resources.DbManager_InvalidDataProviderName, "providerName");
dataProvider.UniqueName = providerName;
AddDataProvider(dataProvider);
}
///
/// Adds a new data provider.
///
///
/// The method can be used to register a new data provider for further use.
///
///
///
/// A data provider type.
public static void AddDataProvider(Type dataProviderType)
{
AddDataProvider((DataProviderBase)Activator.CreateInstance(dataProviderType));
}
///
/// Adds a new data provider witch a specified name.
///
///
/// The method can be used to register a new data provider for further use.
///
///
///
/// The data provider name.
/// A data provider type.
public static void AddDataProvider(string providerName, Type dataProviderType)
{
AddDataProvider(providerName, (DataProviderBase)Activator.CreateInstance(dataProviderType));
}
#endregion
#region AddConnectionString
///
/// Adds a new connection string or replaces existing one.
///
///
/// Use this method when you use only one configuration and
/// you don't want to use a configuration file.
///
///
/// A valid database connection string.
public static void AddConnectionString(string connectionString)
{
AddConnectionString(string.Empty, connectionString);
}
///
/// Adds a new connection string or replaces existing one.
///
///
/// Use this method when you use multiple configurations and
/// you don't want to use a configuration file.
///
///
/// The configuration string.
/// A valid database connection string.
public static void AddConnectionString(string configurationString, string connectionString)
{
_connectionStringList[configurationString] = connectionString;
}
///
/// Adds a new connection string or replaces existing one.
///
///
/// Use this method when you use multiple configurations and
/// you don't want to use a configuration file.
///
///
/// The data provider name.
/// The configuration string.
/// A valid database connection string.
public static void AddConnectionString(
string providerName, string configurationString, string connectionString)
{
AddConnectionString(providerName + ProviderNameDivider + configurationString, connectionString);
}
#endregion
#region Public Static Properties
public const string ProviderNameDivider = ".";
public const string AnyProvider = "*" + ProviderNameDivider;
private static readonly string _defaultDataProviderName;
private static string _defaultConfiguration;
///
/// Gets and sets the default configuration string.
///
///
/// See the property
/// for an explanation and use of the default configuration.
///
///
/// A string containing default configuration settings.
///
///
public static string DefaultConfiguration
{
get
{
if (_defaultConfiguration == null)
{
// Grab first registered configuration.
//
foreach (KeyValuePair de in _connectionStringList)
{
_defaultConfiguration = de.Key;
break;
}
if (_defaultConfiguration == null)
{
_defaultConfiguration = string.Empty;
foreach (ConnectionStringSettings css in ConfigurationManager.ConnectionStrings)
{
if (css.ElementInformation.Source != null &&
!css.ElementInformation.Source.EndsWith("machine.config", StringComparison.OrdinalIgnoreCase))
{
_defaultConfiguration = css.Name;
break;
}
}
}
}
return _defaultConfiguration;
}
set { _defaultConfiguration = value; }
}
#endregion
}
}