#region Apache Notice /***************************************************************************** * $Header: $ * $Revision: $ * $Date: $ * * iBATIS.NET Data Mapper * Copyright (C) 2004 - Gilles Bayon * * * 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 System.Data.Common; using System.Reflection; using IBatisNet.Common.Exceptions; namespace IBatisNet.Common.Utilities { /// /// DBHelperParameterCache provides functions to leverage a /// static cache of procedure parameters, and the /// ability to discover parameters for stored procedures at run-time. /// public class DBHelperParameterCache { //Since this class provides only static methods, make the default constructor private to prevent //instances from being created. private DBHelperParameterCache() {} #region Private fields private static Hashtable _paramCache = Hashtable.Synchronized(new Hashtable()); #endregion #region private methods /// /// Resolve at run time the appropriate set of Parameters for a stored procedure /// /// a valid session /// the name of the stored procedure /// whether or not to include their return value parameter /// private static IDataParameter[] DiscoverSpParameterSet(IDalSession session, string spName, bool includeReturnValueParameter) { using (IDbConnection connection = session.DataSource.Provider.GetConnection()) { connection.ConnectionString = session.DataSource.ConnectionString; connection.Open(); return InternalDiscoverSpParameterSet(session.DataSource.Provider, connection, spName, includeReturnValueParameter); } } /// /// resolve at run time the appropriate set of Parameters for a stored procedure /// /// /// a valid open IDbConnection /// the name of the stored procedure /// whether or not to include their return value parameter /// private static IDataParameter[] InternalDiscoverSpParameterSet(Provider provider, IDbConnection connection, string spName, bool includeReturnValueParameter) { using (IDbCommand cmd = connection.CreateCommand()) { cmd.CommandType = CommandType.StoredProcedure; cmd.CommandText = spName; DeriveParameters(provider, cmd); if (cmd.Parameters.Count > 0) { IDataParameter firstParameter = (IDataParameter)cmd.Parameters[0]; if (firstParameter.Direction == ParameterDirection.ReturnValue) { if (!includeReturnValueParameter) { cmd.Parameters.RemoveAt(0); } } } IDataParameter[] discoveredParameters = new IDataParameter[cmd.Parameters.Count]; cmd.Parameters.CopyTo(discoveredParameters, 0); return discoveredParameters; } } private static void DeriveParameters(Provider provider, IDbCommand command) { Type commandBuilderType; // Find the CommandBuilder if (provider == null) throw new ArgumentNullException("provider"); if ((provider.CommandBuilderClass == null) || (provider.CommandBuilderClass.Length < 1)) throw new Exception(String.Format( "CommandBuilderClass not defined for provider \"{0}\".", provider.Name)); commandBuilderType = provider.GetCommandBuilderType(); // Invoke the static DeriveParameter method on the CommandBuilder class // NOTE: OracleCommandBuilder has no DeriveParameter method try { commandBuilderType.InvokeMember("DeriveParameters", BindingFlags.Public | BindingFlags.InvokeMethod | BindingFlags.Static, null, null, new object[] {command}); } catch(Exception ex) { throw new IBatisNetException("Could not retrieve parameters for the store procedure named "+command.CommandText, ex); } } /// /// Deep copy of cached IDataParameter array. /// /// /// private static IDataParameter[] CloneParameters(IDataParameter[] originalParameters) { IDataParameter[] clonedParameters = new IDataParameter[originalParameters.Length]; for (int i = 0, j = originalParameters.Length; i < j; i++) { clonedParameters[i] = (IDataParameter) ((ICloneable) originalParameters[i]).Clone(); } return clonedParameters; } #endregion private methods, variables, and constructors #region caching functions /// /// Add parameter array to the cache /// /// a valid connection string for an IDbConnection /// the stored procedure name or SQL command /// an array of IDataParameters to be cached public static void CacheParameterSet(string connectionString, string commandText, params IDataParameter[] commandParameters) { string hashKey = connectionString + ":" + commandText; _paramCache[hashKey] = commandParameters; } // FM Added /// /// Clear the parameter cache. /// public static void Clear() { _paramCache.Clear(); } /// /// retrieve a parameter array from the cache /// /// a valid connection string for an IDbConnection /// the stored procedure name or SQL command /// an array of IDataParameters public static IDataParameter[] GetCachedParameterSet(string connectionString, string commandText) { string hashKey = connectionString + ":" + commandText; IDataParameter[] cachedParameters = (IDataParameter[]) _paramCache[hashKey]; if (cachedParameters == null) { return null; } else { return CloneParameters(cachedParameters); } } #endregion caching functions #region Parameter Discovery Functions /// /// Retrieves the set of IDataParameters appropriate for the stored procedure /// /// /// This method will query the database for this information, and then store it in a cache for future requests. /// /// a valid session /// the name of the stored procedure /// an array of IDataParameters public static IDataParameter[] GetSpParameterSet(IDalSession session, string spName) { return GetSpParameterSet(session, spName, false); } /// /// Retrieves the set of IDataParameters appropriate for the stored procedure /// /// /// This method will query the database for this information, and then store it in a cache for future requests. /// /// a valid csession /// the name of the stored procedure /// a bool value indicating whether the return value parameter should be included in the results /// an array of IDataParameters public static IDataParameter[] GetSpParameterSet(IDalSession session , string spName, bool includeReturnValueParameter) { string hashKey = session.DataSource.ConnectionString + ":" + spName + (includeReturnValueParameter ? ":include ReturnValue Parameter":""); IDataParameter[] cachedParameters; cachedParameters = (IDataParameter[]) _paramCache[hashKey]; if (cachedParameters == null) { _paramCache[hashKey] = DiscoverSpParameterSet(session, spName, includeReturnValueParameter); cachedParameters = (IDataParameter[]) _paramCache[hashKey]; } return CloneParameters(cachedParameters); } #endregion Parameter Discovery Functions } }