From 4018ddf2633c50e6bc12090820ae19b7b64c7336 Mon Sep 17 00:00:00 2001 From: markpollack Date: Wed, 13 Aug 2008 21:51:03 +0000 Subject: [PATCH] SPRNET-999 - Add DefaultDbProvider property to MultiDelegatingDbProvider. --- .../Data/Common/MultiDelegatingDbProvider.cs | 547 +++++++++--------- 1 file changed, 281 insertions(+), 266 deletions(-) diff --git a/src/Spring/Spring.Data/Data/Common/MultiDelegatingDbProvider.cs b/src/Spring/Spring.Data/Data/Common/MultiDelegatingDbProvider.cs index 83620328..7221d873 100644 --- a/src/Spring/Spring.Data/Data/Common/MultiDelegatingDbProvider.cs +++ b/src/Spring/Spring.Data/Data/Common/MultiDelegatingDbProvider.cs @@ -1,268 +1,283 @@ -#region Licence - -/* - * Copyright © 2002-2007 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#endregion - -using System; -using System.Collections; -using System.Data; -using Spring.Collections; -using Spring.Dao; -using Spring.Data.Common; -using Spring.Objects.Factory; -using Spring.Threading; - - -namespace Spring.Data -{ - /// - /// A wrapper implementation for IDbProvider such that multiple DbProvider instances can be - /// selected at runtime, say based on web request criteria. - /// - /// - /// The name of which DbProvider to use, as provided to the IDictionary property TargetDbProviders +#region Licence + +/* + * Copyright © 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#endregion + +using System; +using System.Collections; +using System.Data; +using Spring.Collections; +using Spring.Dao; +using Spring.Data.Common; +using Spring.Objects.Factory; +using Spring.Threading; + + +namespace Spring.Data +{ + /// + /// A wrapper implementation for IDbProvider such that multiple DbProvider instances can be + /// selected at runtime, say based on web request criteria. + /// + /// + /// The name of which DbProvider to use, as provided to the IDictionary property TargetDbProviders /// is "dbProviderName". Once the target dbprovider name is known, set the name via a call to - /// LogicalThreadContext.SetData(MultiDelegatingDbProvider.CURRENT_DBPROVIDER_SLOTNAME, "database1ProviderName"). The value - /// "database1ProviderName" must match a key in the provided TargetDbProviders dictionary. - /// - /// Mark Pollack - public class MultiDelegatingDbProvider : IDbProvider, IInitializingObject + /// LogicalThreadContext.SetData(MultiDelegatingDbProvider.CURRENT_DBPROVIDER_SLOTNAME, "database1ProviderName"). The value + /// "database1ProviderName" must match a key in the provided TargetDbProviders dictionary. + /// + /// Mark Pollack + public class MultiDelegatingDbProvider : IDbProvider, IInitializingObject { - private static readonly string CURRENT_DBPROVIDER_SLOTNAME = Spring.Util.UniqueKey.GetTypeScopedString(typeof(MultiDelegatingDbProvider), "Current"); - - private IDictionary targetDbProviders = new SynchronizedHashtable(); - - #region Constructors - /// - /// Initializes a new instance of the class. - /// - public MultiDelegatingDbProvider() - { - - } - - /// - /// Initializes a new instance of the class. - /// - /// The target db providers. - public MultiDelegatingDbProvider(IDictionary targetDbProviders) - { - this.targetDbProviders = targetDbProviders; - } - - #endregion - - /// - /// Sets the target db providers. - /// - /// The target db providers. - public IDictionary TargetDbProviders - { - set { targetDbProviders = value; } - } - - /// - /// Ensures that the there are values in the TargetDbProviders dictionary and that the - /// key is of the type string and value is of the type IDbProvider. - /// - /// If the above conditions are not met. - public void AfterPropertiesSet() - { - if (targetDbProviders.Count == 0) - { - throw new ArgumentException("Target DbProvider collection required."); - } - foreach (DictionaryEntry entry in targetDbProviders) - { - if (! entry.Key.GetType().Equals(typeof(string))) - { - throw new ArgumentException("Key identifying target IDbProvider in TargetDbProviders dictionary property is required to be of type string. Key = " + entry.Key); - } - IDbProvider targetProvider = entry.Value as IDbProvider; - if (targetProvider == null) - { - throw new ArgumentException("Value in TargetDbProviders dictionary is not of type IDbProvider."); - } - } - } - - #region IDbProvider methods - - - /// - /// Returns a new command object for executing SQL statments/Stored Procedures - /// against the database. - /// - /// An new - public IDbCommand CreateCommand() - { - return GetTargetProvider().CreateCommand(); - } - - /// - /// Returns a new connection object to communicate with the database. - /// - /// A new - public IDbConnection CreateConnection() - { - return GetTargetProvider().CreateConnection(); - } - - /// - /// Returns a new parameter object for binding values to parameter - /// placeholders in SQL statements or Stored Procedure variables. - /// - /// A new - public IDbDataParameter CreateParameter() - { - return GetTargetProvider().CreateParameter(); - } - - /// - /// Returns a new adapter objects for use with offline DataSets. - /// - /// A new - public IDbDataAdapter CreateDataAdapter() - { - return GetTargetProvider().CreateDataAdapter(); - } - - /// - /// Returns a new instance of the providers CommandBuilder class. - /// - /// A new Command Builder - /// In .NET 1.1 there was no common base class or interface - /// for command builders, hence the return signature is object to - /// be portable (but more loosely typed) across .NET 1.1/2.0 - public object CreateCommandBuilder() - { - return GetTargetProvider().CreateDataAdapter(); - } - - /// - /// Creates the name of the parameter in the format appropriate to use inside IDbCommand.CommandText. - /// - /// The unformatted name of the parameter. - /// - /// The parameter name formatted foran IDbCommand.CommandText. - /// - /// In most cases this adds the parameter prefix to the name passed into this method. - public string CreateParameterName(string name) - { - return GetTargetProvider().CreateParameterName(name); - } - - - /// - /// Creates the name ofthe parameter in the format appropriate for an IDataParameter, i.e. to be - /// part of a IDataParameterCollection. - /// - /// The unformatted name of the parameter. - /// - /// The parameter name formatted for an IDataParameter - /// - public string CreateParameterNameForCollection(string name) - { - return GetTargetProvider().CreateParameterNameForCollection(name); - } - - /// - /// Return metadata information about the database provider - /// - /// - public IDbMetadata DbMetadata - { - get { return GetTargetProvider().DbMetadata; } - } - - /// - /// Connection string used to create connections. - /// - /// - public string ConnectionString - { - get { return GetTargetProvider().ConnectionString; } - set { GetTargetProvider().ConnectionString = value; } - } - - /// - /// Extracts the provider specific error code as a string. - /// - /// The data access exception. - /// The provider specific error code - public string ExtractError(Exception e) - { - return GetTargetProvider().ExtractError(e); - } - - /// - /// Determines whether the provided exception is in fact related - /// to database access. This can be provider dependent in .NET 1.1 since - /// there isn't a common base class for ADO.NET exceptions. - /// - /// The exception thrown when performing data access - /// operations. - /// - /// true if is a valid data access exception for the specified - /// exception; otherwise, false. - /// - public bool IsDataAccessException(Exception e) - { -#if NET_2_0 - if (e is System.Data.Common.DbException) - { - return true; - } - else - { - return false; - } -#else - return IsDataAccessExceptionBCL11(e); -#endif - } - - /// - /// Determines whether is data access exception in .NET 1.1 for the specified exception. - /// - /// The candidate exception. - /// - /// true if is data access exception in .NET 1.1 for the specified exception; otherwise, false. - /// - public bool IsDataAccessExceptionBCL11(Exception e) - { - return false; - } - #endregion - - /// - /// Gets the target provider based on the thread local name "dbProviderName" - /// - /// The corresonding IDbProvider. - protected virtual IDbProvider GetTargetProvider() + private static readonly string CURRENT_DBPROVIDER_SLOTNAME = Spring.Util.UniqueKey.GetTypeScopedString(typeof(MultiDelegatingDbProvider), "Current"); + + private IDbProvider defaultDbProvider; + + private IDictionary targetDbProviders = new SynchronizedHashtable(); + + #region Constructors + /// + /// Initializes a new instance of the class. + /// + public MultiDelegatingDbProvider() { - string dbProviderName = (string)LogicalThreadContext.GetData(CURRENT_DBPROVIDER_SLOTNAME); - if (targetDbProviders.Contains(dbProviderName)) - { - return (IDbProvider)targetDbProviders[dbProviderName]; - } - throw new InvalidDataAccessApiUsageException("'" + dbProviderName + "'" - + "was not under the thread local key 'dbProviderName'"); + + } + + /// + /// Initializes a new instance of the class. + /// + /// The target db providers. + public MultiDelegatingDbProvider(IDictionary targetDbProviders) + { + this.targetDbProviders = targetDbProviders; + } + + #endregion + + /// + /// Sets the default IDbProvider. This will be returned if no DbProvider is found in thread local storage. + /// + /// The default db provider. + public IDbProvider DefaultDbProvider + { + set { defaultDbProvider = value; } + } + + /// + /// Sets the target db providers. + /// + /// The target db providers. + public IDictionary TargetDbProviders + { + set { targetDbProviders = value; } + } + + /// + /// Ensures that the there are values in the TargetDbProviders dictionary and that the + /// key is of the type string and value is of the type IDbProvider. + /// + /// If the above conditions are not met. + public void AfterPropertiesSet() + { + if (targetDbProviders.Count == 0) + { + throw new ArgumentException("Target DbProvider collection required."); + } + foreach (DictionaryEntry entry in targetDbProviders) + { + if (! entry.Key.GetType().Equals(typeof(string))) + { + throw new ArgumentException("Key identifying target IDbProvider in TargetDbProviders dictionary property is required to be of type string. Key = " + entry.Key); + } + IDbProvider targetProvider = entry.Value as IDbProvider; + if (targetProvider == null) + { + throw new ArgumentException("Value in TargetDbProviders dictionary is not of type IDbProvider."); + } + } + } + + #region IDbProvider methods + + + /// + /// Returns a new command object for executing SQL statments/Stored Procedures + /// against the database. + /// + /// An new + public IDbCommand CreateCommand() + { + return GetTargetProvider().CreateCommand(); + } + + /// + /// Returns a new connection object to communicate with the database. + /// + /// A new + public IDbConnection CreateConnection() + { + return GetTargetProvider().CreateConnection(); + } + + /// + /// Returns a new parameter object for binding values to parameter + /// placeholders in SQL statements or Stored Procedure variables. + /// + /// A new + public IDbDataParameter CreateParameter() + { + return GetTargetProvider().CreateParameter(); + } + + /// + /// Returns a new adapter objects for use with offline DataSets. + /// + /// A new + public IDbDataAdapter CreateDataAdapter() + { + return GetTargetProvider().CreateDataAdapter(); + } + + /// + /// Returns a new instance of the providers CommandBuilder class. + /// + /// A new Command Builder + /// In .NET 1.1 there was no common base class or interface + /// for command builders, hence the return signature is object to + /// be portable (but more loosely typed) across .NET 1.1/2.0 + public object CreateCommandBuilder() + { + return GetTargetProvider().CreateDataAdapter(); + } + + /// + /// Creates the name of the parameter in the format appropriate to use inside IDbCommand.CommandText. + /// + /// The unformatted name of the parameter. + /// + /// The parameter name formatted foran IDbCommand.CommandText. + /// + /// In most cases this adds the parameter prefix to the name passed into this method. + public string CreateParameterName(string name) + { + return GetTargetProvider().CreateParameterName(name); + } + + + /// + /// Creates the name ofthe parameter in the format appropriate for an IDataParameter, i.e. to be + /// part of a IDataParameterCollection. + /// + /// The unformatted name of the parameter. + /// + /// The parameter name formatted for an IDataParameter + /// + public string CreateParameterNameForCollection(string name) + { + return GetTargetProvider().CreateParameterNameForCollection(name); + } + + /// + /// Return metadata information about the database provider + /// + /// + public IDbMetadata DbMetadata + { + get { return GetTargetProvider().DbMetadata; } + } + + /// + /// Connection string used to create connections. + /// + /// + public string ConnectionString + { + get { return GetTargetProvider().ConnectionString; } + set { GetTargetProvider().ConnectionString = value; } + } + + /// + /// Extracts the provider specific error code as a string. + /// + /// The data access exception. + /// The provider specific error code + public string ExtractError(Exception e) + { + return GetTargetProvider().ExtractError(e); + } + + /// + /// Determines whether the provided exception is in fact related + /// to database access. This can be provider dependent in .NET 1.1 since + /// there isn't a common base class for ADO.NET exceptions. + /// + /// The exception thrown when performing data access + /// operations. + /// + /// true if is a valid data access exception for the specified + /// exception; otherwise, false. + /// + public bool IsDataAccessException(Exception e) + { +#if NET_2_0 + if (e is System.Data.Common.DbException) + { + return true; + } + else + { + return false; + } +#else + return IsDataAccessExceptionBCL11(e); +#endif + } + + /// + /// Determines whether is data access exception in .NET 1.1 for the specified exception. + /// + /// The candidate exception. + /// + /// true if is data access exception in .NET 1.1 for the specified exception; otherwise, false. + /// + public bool IsDataAccessExceptionBCL11(Exception e) + { + return false; + } + #endregion + + /// + /// Gets the target provider based on the thread local name "dbProviderName" + /// + /// The corresonding IDbProvider. + protected virtual IDbProvider GetTargetProvider() + { + string dbProviderName = (string)LogicalThreadContext.GetData(CURRENT_DBPROVIDER_SLOTNAME); + if (targetDbProviders.Contains(dbProviderName)) + { + return (IDbProvider)targetDbProviders[dbProviderName]; + } + if (defaultDbProvider != null) + { + return defaultDbProvider; + } + throw new InvalidDataAccessApiUsageException("'" + dbProviderName + "'" + + "was not under the thread local key 'dbProviderName'"); } /// @@ -270,12 +285,12 @@ namespace Spring.Data /// the current thread's procesing. /// /// The name of the DbProvider to use for the current threads processing. - public static string CurrentDbProviderName + public static string CurrentDbProviderName { set { LogicalThreadContext.SetData(CURRENT_DBPROVIDER_SLOTNAME, value); } - } - } -} + } + } +}