#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
}
}