SQLHelper

   1 // ===============================================================================
   2 // Microsoft Data Access Application Block for .NET
   3 // http://msdn.microsoft.com/library/en-us/dnbda/html/daab-rm.asp
   4 //
   5 // SQLHelper.cs
   6 //
   7 // This file contains the implementations of the SqlHelper and SqlHelperParameterCache
   8 // classes.
   9 //
  10 // For more information see the Data Access Application Block Implementation Overview. 
  11 // ===============================================================================
  12 // Release history
  13 // VERSION    DESCRIPTION
  14 //   2.0    Added support for FillDataset, UpdateDataset and "Param" helper methods
  15 //
  16 // ===============================================================================
  17 // Copyright (C) 2000-2001 Microsoft Corporation
  18 // All rights reserved.
  19 // THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY
  20 // OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT
  21 // LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR
  22 // FITNESS FOR A PARTICULAR PURPOSE.
  23 // ==============================================================================
  24 
  25 using System;
  26 using System.Data;
  27 using System.Xml;
  28 using System.Data.SqlClient;
  29 using System.Collections;
  30 
  31 namespace F.Studio.Data.Util
  32 {
  33     /// <summary>
  34     /// The SqlHelper class is intended to encapsulate high performance, scalable best practices for 
  35     /// common uses of SqlClient
  36     /// </summary>
  37     public sealed class SqlHelper
  38     {
  39         #region private utility methods & constructors
  40 
  41         // Since this class provides only static methods, make the default constructor private to prevent 
  42         // instances from being created with "new SqlHelper()"
  43         private SqlHelper() {}
  44 
  45         /// <summary>
  46         /// This method is used to attach array of SqlParameters to a SqlCommand.
  47         /// 
  48         /// This method will assign a value of DbNull to any parameter with a direction of
  49         /// InputOutput and a value of null.  
  50         /// 
  51         /// This behavior will prevent default values from being used, but
  52         /// this will be the less common case than an intended pure output parameter (derived as InputOutput)
  53         /// where the user provided no input value.
  54         /// </summary>
  55         /// <param name="command">The command to which the parameters will be added</param>
  56         /// <param name="commandParameters">An array of SqlParameters to be added to command</param>
  57         private static void AttachParameters(SqlCommand command, SqlParameter[] commandParameters)
  58         {
  59             if( command == null ) throw new ArgumentNullException( "command" );
  60             if( commandParameters != null )
  61             {
  62                 foreach (SqlParameter p in commandParameters)
  63                 {
  64                     if( p != null )
  65                     {
  66                         // Check for derived output value with no value assigned
  67                         if ( ( p.Direction == ParameterDirection.InputOutput || 
  68                             p.Direction == ParameterDirection.Input ) && 
  69                             (p.Value == null))
  70                         {
  71                             p.Value = DBNull.Value;
  72                         }
  73                         command.Parameters.Add(p);
  74                     }
  75                 }
  76             }
  77         }
  78 
  79         /// <summary>
  80         /// This method assigns dataRow column values to an array of SqlParameters
  81         /// </summary>
  82         /// <param name="commandParameters">Array of SqlParameters to be assigned values</param>
  83         /// <param name="dataRow">The dataRow used to hold the stored procedure's parameter values</param>
  84         private static void AssignParameterValues(SqlParameter[] commandParameters, DataRow dataRow)
  85         {
  86             if ((commandParameters == null) || (dataRow == null)) 
  87             {
  88                 // Do nothing if we get no data
  89                 return;
  90             }
  91 
  92             int i = 0;
  93             // Set the parameters values
  94             foreach(SqlParameter commandParameter in commandParameters)
  95             {
  96                 // Check the parameter name
  97                 if( commandParameter.ParameterName == null || 
  98                     commandParameter.ParameterName.Length <= 1 )
  99                     throw new Exception( 
 100                         string.Format( 
 101                             "Please provide a valid parameter name on the parameter #{0}, the ParameterName property has the following value: '{1}'.", 
 102                             i, commandParameter.ParameterName ) );
 103                 if (dataRow.Table.Columns.IndexOf(commandParameter.ParameterName.Substring(1)) != -1)
 104                     commandParameter.Value = dataRow[commandParameter.ParameterName.Substring(1)];
 105                 i++;
 106             }
 107         }
 108 
 109         /// <summary>
 110         /// This method assigns an array of values to an array of SqlParameters
 111         /// </summary>
 112         /// <param name="commandParameters">Array of SqlParameters to be assigned values</param>
 113         /// <param name="parameterValues">Array of objects holding the values to be assigned</param>
 114         private static void AssignParameterValues(SqlParameter[] commandParameters, object[] parameterValues)
 115         {
 116             if ((commandParameters == null) || (parameterValues == null)) 
 117             {
 118                 // Do nothing if we get no data
 119                 return;
 120             }
 121 
 122             // We must have the same number of values as we pave parameters to put them in
 123             if (commandParameters.Length != parameterValues.Length)
 124             {
 125                 throw new ArgumentException("Parameter count does not match Parameter Value count.");
 126             }
 127 
 128             // Iterate through the SqlParameters, assigning the values from the corresponding position in the 
 129             // value array
 130             for (int i = 0, j = commandParameters.Length; i < j; i++)
 131             {
 132                 // If the current array value derives from IDbDataParameter, then assign its Value property
 133                 if (parameterValues[i] is IDbDataParameter)
 134                 {
 135                     IDbDataParameter paramInstance = (IDbDataParameter)parameterValues[i];
 136                     if( paramInstance.Value == null )
 137                     {
 138                         commandParameters[i].Value = DBNull.Value; 
 139                     }
 140                     else
 141                     {
 142                         commandParameters[i].Value = paramInstance.Value;
 143                     }
 144                 }
 145                 else if (parameterValues[i] == null)
 146                 {
 147                     commandParameters[i].Value = DBNull.Value;
 148                 }
 149                 else
 150                 {
 151                     commandParameters[i].Value = parameterValues[i];
 152                 }
 153             }
 154         }
 155 
 156         /// <summary>
 157         /// This method opens (if necessary) and assigns a connection, transaction, command type and parameters 
 158         /// to the provided command
 159         /// </summary>
 160         /// <param name="command">The SqlCommand to be prepared</param>
 161         /// <param name="connection">A valid SqlConnection, on which to execute this command</param>
 162         /// <param name="transaction">A valid SqlTransaction, or 'null'</param>
 163         /// <param name="commandType">The CommandType (stored procedure, text, etc.)</param>
 164         /// <param name="commandText">The stored procedure name or T-SQL command</param>
 165         /// <param name="commandParameters">An array of SqlParameters to be associated with the command or 'null' if no parameters are required</param>
 166         /// <param name="mustCloseConnection"><c>true</c> if the connection was opened by the method, otherwose is false.</param>
 167         private static void PrepareCommand(SqlCommand command, SqlConnection connection, SqlTransaction transaction, CommandType commandType, string commandText, SqlParameter[] commandParameters, out bool mustCloseConnection )
 168         {
 169             if( command == null ) throw new ArgumentNullException( "command" );
 170             if( commandText == null || commandText.Length == 0 ) throw new ArgumentNullException( "commandText" );
 171 
 172             // If the provided connection is not open, we will open it
 173             if (connection.State != ConnectionState.Open)
 174             {
 175                 mustCloseConnection = true;
 176                 connection.Open();
 177             }
 178             else
 179             {
 180                 mustCloseConnection = false;
 181             }
 182 
 183             // Associate the connection with the command
 184             command.Connection = connection;
 185 
 186             // Set the command text (stored procedure name or SQL statement)
 187             command.CommandText = commandText;
 188 
 189             // If we were provided a transaction, assign it
 190             if (transaction != null)
 191             {
 192                 if( transaction.Connection == null ) throw new ArgumentException( "The transaction was rollbacked or commited, please provide an open transaction.", "transaction" );
 193                 command.Transaction = transaction;
 194             }
 195 
 196             // Set the command type
 197             command.CommandType = commandType;
 198 
 199             // Attach the command parameters if they are provided
 200             if (commandParameters != null)
 201             {
 202                 AttachParameters(command, commandParameters);
 203             }
 204             return;
 205         }
 206 
 207         #endregion private utility methods & constructors
 208 
 209         #region ExecuteNonQuery
 210 
 211         /// <summary>
 212         /// Execute a SqlCommand (that returns no resultset and takes no parameters) against the database specified in 
 213         /// the connection string
 214         /// </summary>
 215         /// <remarks>
 216         /// e.g.:  
 217         ///  int result = ExecuteNonQuery(connString, CommandType.StoredProcedure, "PublishOrders");
 218         /// </remarks>
 219         /// <param name="connectionString">A valid connection string for a SqlConnection</param>
 220         /// <param name="commandType">The CommandType (stored procedure, text, etc.)</param>
 221         /// <param name="commandText">The stored procedure name or T-SQL command</param>
 222         /// <returns>An int representing the number of rows affected by the command</returns>
 223         public static int ExecuteNonQuery(string connectionString, CommandType commandType, string commandText)
 224         {
 225             // Pass through the call providing null for the set of SqlParameters
 226             return ExecuteNonQuery(connectionString, commandType, commandText, (SqlParameter[])null);
 227         }
 228 
 229         /// <summary>
 230         /// Execute a SqlCommand (that returns no resultset) against the database specified in the connection string 
 231         /// using the provided parameters
 232         /// </summary>
 233         /// <remarks>
 234         /// e.g.:  
 235         ///  int result = ExecuteNonQuery(connString, CommandType.StoredProcedure, "PublishOrders", new SqlParameter("@prodid", 24));
 236         /// </remarks>
 237         /// <param name="connectionString">A valid connection string for a SqlConnection</param>
 238         /// <param name="commandType">The CommandType (stored procedure, text, etc.)</param>
 239         /// <param name="commandText">The stored procedure name or T-SQL command</param>
 240         /// <param name="commandParameters">An array of SqlParamters used to execute the command</param>
 241         /// <returns>An int representing the number of rows affected by the command</returns>
 242         public static int ExecuteNonQuery(string connectionString, CommandType commandType, string commandText, params SqlParameter[] commandParameters)
 243         {
 244             if( connectionString == null || connectionString.Length == 0 ) throw new ArgumentNullException( "connectionString" );
 245 
 246             // Create & open a SqlConnection, and dispose of it after we are done
 247             using (SqlConnection connection = new SqlConnection(connectionString))
 248             {
 249                 connection.Open();
 250 
 251                 // Call the overload that takes a connection in place of the connection string
 252                 return ExecuteNonQuery(connection, commandType, commandText, commandParameters);
 253             }
 254         }
 255 
 256         /// <summary>
 257         /// Execute a stored procedure via a SqlCommand (that returns no resultset) against the database specified in 
 258         /// the connection string using the provided parameter values.  This method will query the database to discover the parameters for the 
 259         /// stored procedure (the first time each stored procedure is called), and assign the values based on parameter order.
 260         /// </summary>
 261         /// <remarks>
 262         /// This method provides no access to output parameters or the stored procedure's return value parameter.
 263         /// 
 264         /// e.g.:  
 265         ///  int result = ExecuteNonQuery(connString, "PublishOrders", 24, 36);
 266         /// </remarks>
 267         /// <param name="connectionString">A valid connection string for a SqlConnection</param>
 268         /// <param name="spName">The name of the stored prcedure</param>
 269         /// <param name="parameterValues">An array of objects to be assigned as the input values of the stored procedure</param>
 270         /// <returns>An int representing the number of rows affected by the command</returns>
 271         public static int ExecuteNonQuery(string connectionString, string spName, params object[] parameterValues)
 272         {
 273             if( connectionString == null || connectionString.Length == 0 ) throw new ArgumentNullException( "connectionString" );
 274             if( spName == null || spName.Length == 0 ) throw new ArgumentNullException( "spName" );
 275 
 276             // If we receive parameter values, we need to figure out where they go
 277             if ((parameterValues != null) && (parameterValues.Length > 0)) 
 278             {
 279                 // Pull the parameters for this stored procedure from the parameter cache (or discover them & populate the cache)
 280                 SqlParameter[] commandParameters = SqlHelperParameterCache.GetSpParameterSet(connectionString, spName);
 281 
 282                 // Assign the provided values to these parameters based on parameter order
 283                 AssignParameterValues(commandParameters, parameterValues);
 284 
 285                 // Call the overload that takes an array of SqlParameters
 286                 return ExecuteNonQuery(connectionString, CommandType.StoredProcedure, spName, commandParameters);
 287             }
 288             else 
 289             {
 290                 // Otherwise we can just call the SP without params
 291                 return ExecuteNonQuery(connectionString, CommandType.StoredProcedure, spName);
 292             }
 293         }
 294 
 295         /// <summary>
 296         /// Execute a SqlCommand (that returns no resultset and takes no parameters) against the provided SqlConnection. 
 297         /// </summary>
 298         /// <remarks>
 299         /// e.g.:  
 300         ///  int result = ExecuteNonQuery(conn, CommandType.StoredProcedure, "PublishOrders");
 301         /// </remarks>
 302         /// <param name="connection">A valid SqlConnection</param>
 303         /// <param name="commandType">The CommandType (stored procedure, text, etc.)</param>
 304         /// <param name="commandText">The stored procedure name or T-SQL command</param>
 305         /// <returns>An int representing the number of rows affected by the command</returns>
 306         public static int ExecuteNonQuery(SqlConnection connection, CommandType commandType, string commandText)
 307         {
 308             // Pass through the call providing null for the set of SqlParameters
 309             return ExecuteNonQuery(connection, commandType, commandText, (SqlParameter[])null);
 310         }
 311 
 312         /// <summary>
 313         /// Execute a SqlCommand (that returns no resultset) against the specified SqlConnection 
 314         /// using the provided parameters.
 315         /// </summary>
 316         /// <remarks>
 317         /// e.g.:  
 318         ///  int result = ExecuteNonQuery(conn, CommandType.StoredProcedure, "PublishOrders", new SqlParameter("@prodid", 24));
 319         /// </remarks>
 320         /// <param name="connection">A valid SqlConnection</param>
 321         /// <param name="commandType">The CommandType (stored procedure, text, etc.)</param>
 322         /// <param name="commandText">The stored procedure name or T-SQL command</param>
 323         /// <param name="commandParameters">An array of SqlParamters used to execute the command</param>
 324         /// <returns>An int representing the number of rows affected by the command</returns>
 325         public static int ExecuteNonQuery(SqlConnection connection, CommandType commandType, string commandText, params SqlParameter[] commandParameters)
 326         {    
 327             if( connection == null ) throw new ArgumentNullException( "connection" );
 328 
 329             // Create a command and prepare it for execution
 330             SqlCommand cmd = new SqlCommand();
 331             bool mustCloseConnection = false;
 332             PrepareCommand(cmd, connection, (SqlTransaction)null, commandType, commandText, commandParameters, out mustCloseConnection );
 333             
 334             // Finally, execute the command
 335             int retval = cmd.ExecuteNonQuery();
 336             
 337             // Detach the SqlParameters from the command object, so they can be used again
 338             cmd.Parameters.Clear();
 339             if( mustCloseConnection )
 340                 connection.Close();
 341             return retval;
 342         }
 343 
 344         /// <summary>
 345         /// Execute a stored procedure via a SqlCommand (that returns no resultset) against the specified SqlConnection 
 346         /// using the provided parameter values.  This method will query the database to discover the parameters for the 
 347         /// stored procedure (the first time each stored procedure is called), and assign the values based on parameter order.
 348         /// </summary>
 349         /// <remarks>
 350         /// This method provides no access to output parameters or the stored procedure's return value parameter.
 351         /// 
 352         /// e.g.:  
 353         ///  int result = ExecuteNonQuery(conn, "PublishOrders", 24, 36);
 354         /// </remarks>
 355         /// <param name="connection">A valid SqlConnection</param>
 356         /// <param name="spName">The name of the stored procedure</param>
 357         /// <param name="parameterValues">An array of objects to be assigned as the input values of the stored procedure</param>
 358         /// <returns>An int representing the number of rows affected by the command</returns>
 359         public static int ExecuteNonQuery(SqlConnection connection, string spName, params object[] parameterValues)
 360         {
 361             if( connection == null ) throw new ArgumentNullException( "connection" );
 362             if( spName == null || spName.Length == 0 ) throw new ArgumentNullException( "spName" );
 363 
 364             // If we receive parameter values, we need to figure out where they go
 365             if ((parameterValues != null) && (parameterValues.Length > 0)) 
 366             {
 367                 // Pull the parameters for this stored procedure from the parameter cache (or discover them & populate the cache)
 368                 SqlParameter[] commandParameters = SqlHelperParameterCache.GetSpParameterSet(connection, spName);
 369 
 370                 // Assign the provided values to these parameters based on parameter order
 371                 AssignParameterValues(commandParameters, parameterValues);
 372 
 373                 // Call the overload that takes an array of SqlParameters
 374                 return ExecuteNonQuery(connection, CommandType.StoredProcedure, spName, commandParameters);
 375             }
 376             else 
 377             {
 378                 // Otherwise we can just call the SP without params
 379                 return ExecuteNonQuery(connection, CommandType.StoredProcedure, spName);
 380             }
 381         }
 382 
 383         /// <summary>
 384         /// Execute a SqlCommand (that returns no resultset and takes no parameters) against the provided SqlTransaction. 
 385         /// </summary>
 386         /// <remarks>
 387         /// e.g.:  
 388         ///  int result = ExecuteNonQuery(trans, CommandType.StoredProcedure, "PublishOrders");
 389         /// </remarks>
 390         /// <param name="transaction">A valid SqlTransaction</param>
 391         /// <param name="commandType">The CommandType (stored procedure, text, etc.)</param>
 392         /// <param name="commandText">The stored procedure name or T-SQL command</param>
 393         /// <returns>An int representing the number of rows affected by the command</returns>
 394         public static int ExecuteNonQuery(SqlTransaction transaction, CommandType commandType, string commandText)
 395         {
 396             // Pass through the call providing null for the set of SqlParameters
 397             return ExecuteNonQuery(transaction, commandType, commandText, (SqlParameter[])null);
 398         }
 399 
 400         /// <summary>
 401         /// Execute a SqlCommand (that returns no resultset) against the specified SqlTransaction
 402         /// using the provided parameters.
 403         /// </summary>
 404         /// <remarks>
 405         /// e.g.:  
 406         ///  int result = ExecuteNonQuery(trans, CommandType.StoredProcedure, "GetOrders", new SqlParameter("@prodid", 24));
 407         /// </remarks>
 408         /// <param name="transaction">A valid SqlTransaction</param>
 409         /// <param name="commandType">The CommandType (stored procedure, text, etc.)</param>
 410         /// <param name="commandText">The stored procedure name or T-SQL command</param>
 411         /// <param name="commandParameters">An array of SqlParamters used to execute the command</param>
 412         /// <returns>An int representing the number of rows affected by the command</returns>
 413         public static int ExecuteNonQuery(SqlTransaction transaction, CommandType commandType, string commandText, params SqlParameter[] commandParameters)
 414         {
 415             if( transaction == null ) throw new ArgumentNullException( "transaction" );
 416             if( transaction != null && transaction.Connection == null ) throw new ArgumentException( "The transaction was rollbacked or commited, please provide an open transaction.", "transaction" );
 417 
 418             // Create a command and prepare it for execution
 419             SqlCommand cmd = new SqlCommand();
 420             bool mustCloseConnection = false;
 421             PrepareCommand(cmd, transaction.Connection, transaction, commandType, commandText, commandParameters, out mustCloseConnection );
 422                 
 423             // Finally, execute the command
 424             int retval = cmd.ExecuteNonQuery();
 425                 
 426             // Detach the SqlParameters from the command object, so they can be used again
 427             cmd.Parameters.Clear();
 428             return retval;
 429         }
 430 
 431         /// <summary>
 432         /// Execute a stored procedure via a SqlCommand (that returns no resultset) against the specified 
 433         /// SqlTransaction using the provided parameter values.  This method will query the database to discover the parameters for the 
 434         /// stored procedure (the first time each stored procedure is called), and assign the values based on parameter order.
 435         /// </summary>
 436         /// <remarks>
 437         /// This method provides no access to output parameters or the stored procedure's return value parameter.
 438         /// 
 439         /// e.g.:  
 440         ///  int result = ExecuteNonQuery(conn, trans, "PublishOrders", 24, 36);
 441         /// </remarks>
 442         /// <param name="transaction">A valid SqlTransaction</param>
 443         /// <param name="spName">The name of the stored procedure</param>
 444         /// <param name="parameterValues">An array of objects to be assigned as the input values of the stored procedure</param>
 445         /// <returns>An int representing the number of rows affected by the command</returns>
 446         public static int ExecuteNonQuery(SqlTransaction transaction, string spName, params object[] parameterValues)
 447         {
 448             if( transaction == null ) throw new ArgumentNullException( "transaction" );
 449             if( transaction != null && transaction.Connection == null ) throw new ArgumentException( "The transaction was rollbacked or commited, please provide an open transaction.", "transaction" );
 450             if( spName == null || spName.Length == 0 ) throw new ArgumentNullException( "spName" );
 451 
 452             // If we receive parameter values, we need to figure out where they go
 453             if ((parameterValues != null) && (parameterValues.Length > 0)) 
 454             {
 455                 // Pull the parameters for this stored procedure from the parameter cache (or discover them & populate the cache)
 456                 SqlParameter[] commandParameters = SqlHelperParameterCache.GetSpParameterSet(transaction.Connection, spName);
 457 
 458                 // Assign the provided values to these parameters based on parameter order
 459                 AssignParameterValues(commandParameters, parameterValues);
 460 
 461                 // Call the overload that takes an array of SqlParameters
 462                 return ExecuteNonQuery(transaction, CommandType.StoredProcedure, spName, commandParameters);
 463             }
 464             else 
 465             {
 466                 // Otherwise we can just call the SP without params
 467                 return ExecuteNonQuery(transaction, CommandType.StoredProcedure, spName);
 468             }
 469         }
 470 
 471         #endregion ExecuteNonQuery
 472 
 473         #region ExecuteDataset
 474 
 475         /// <summary>
 476         /// Execute a SqlCommand (that returns a resultset and takes no parameters) against the database specified in 
 477         /// the connection string. 
 478         /// </summary>
 479         /// <remarks>
 480         /// e.g.:  
 481         ///  DataSet ds = ExecuteDataset(connString, CommandType.StoredProcedure, "GetOrders");
 482         /// </remarks>
 483         /// <param name="connectionString">A valid connection string for a SqlConnection</param>
 484         /// <param name="commandType">The CommandType (stored procedure, text, etc.)</param>
 485         /// <param name="commandText">The stored procedure name or T-SQL command</param>
 486         /// <returns>A dataset containing the resultset generated by the command</returns>
 487         public static DataSet ExecuteDataset(string connectionString, CommandType commandType, string commandText)
 488         {
 489             // Pass through the call providing null for the set of SqlParameters
 490             return ExecuteDataset(connectionString, commandType, commandText, (SqlParameter[])null);
 491         }
 492 
 493         /// <summary>
 494         /// Execute a SqlCommand (that returns a resultset) against the database specified in the connection string 
 495         /// using the provided parameters.
 496         /// </summary>
 497         /// <remarks>
 498         /// e.g.:  
 499         ///  DataSet ds = ExecuteDataset(connString, CommandType.StoredProcedure, "GetOrders", new SqlParameter("@prodid", 24));
 500         /// </remarks>
 501         /// <param name="connectionString">A valid connection string for a SqlConnection</param>
 502         /// <param name="commandType">The CommandType (stored procedure, text, etc.)</param>
 503         /// <param name="commandText">The stored procedure name or T-SQL command</param>
 504         /// <param name="commandParameters">An array of SqlParamters used to execute the command</param>
 505         /// <returns>A dataset containing the resultset generated by the command</returns>
 506         public static DataSet ExecuteDataset(string connectionString, CommandType commandType, string commandText, params SqlParameter[] commandParameters)
 507         {
 508             if( connectionString == null || connectionString.Length == 0 ) throw new ArgumentNullException( "connectionString" );
 509 
 510             // Create & open a SqlConnection, and dispose of it after we are done
 511             using (SqlConnection connection = new SqlConnection(connectionString))
 512             {
 513                 connection.Open();
 514 
 515                 // Call the overload that takes a connection in place of the connection string
 516                 return ExecuteDataset(connection, commandType, commandText, commandParameters);
 517             }
 518         }
 519 
 520         /// <summary>
 521         /// Execute a stored procedure via a SqlCommand (that returns a resultset) against the database specified in 
 522         /// the connection string using the provided parameter values.  This method will query the database to discover the parameters for the 
 523         /// stored procedure (the first time each stored procedure is called), and assign the values based on parameter order.
 524         /// </summary>
 525         /// <remarks>
 526         /// This method provides no access to output parameters or the stored procedure's return value parameter.
 527         /// 
 528         /// e.g.:  
 529         ///  DataSet ds = ExecuteDataset(connString, "GetOrders", 24, 36);
 530         /// </remarks>
 531         /// <param name="connectionString">A valid connection string for a SqlConnection</param>
 532         /// <param name="spName">The name of the stored procedure</param>
 533         /// <param name="parameterValues">An array of objects to be assigned as the input values of the stored procedure</param>
 534         /// <returns>A dataset containing the resultset generated by the command</returns>
 535         public static DataSet ExecuteDataset(string connectionString, string spName, params object[] parameterValues)
 536         {
 537             if( connectionString == null || connectionString.Length == 0 ) throw new ArgumentNullException( "connectionString" );
 538             if( spName == null || spName.Length == 0 ) throw new ArgumentNullException( "spName" );
 539             
 540             // If we receive parameter values, we need to figure out where they go
 541             if ((parameterValues != null) && (parameterValues.Length > 0)) 
 542             {
 543                 // Pull the parameters for this stored procedure from the parameter cache (or discover them & populate the cache)
 544                 SqlParameter[] commandParameters = SqlHelperParameterCache.GetSpParameterSet(connectionString, spName);
 545 
 546                 // Assign the provided values to these parameters based on parameter order
 547                 AssignParameterValues(commandParameters, parameterValues);
 548 
 549                 // Call the overload that takes an array of SqlParameters
 550                 return ExecuteDataset(connectionString, CommandType.StoredProcedure, spName, commandParameters);
 551             }
 552             else 
 553             {
 554                 // Otherwise we can just call the SP without params
 555                 return ExecuteDataset(connectionString, CommandType.StoredProcedure, spName);
 556             }
 557         }
 558 
 559         /// <summary>
 560         /// Execute a SqlCommand (that returns a resultset and takes no parameters) against the provided SqlConnection. 
 561         /// </summary>
 562         /// <remarks>
 563         /// e.g.:  
 564         ///  DataSet ds = ExecuteDataset(conn, CommandType.StoredProcedure, "GetOrders");
 565         /// </remarks>
 566         /// <param name="connection">A valid SqlConnection</param>
 567         /// <param name="commandType">The CommandType (stored procedure, text, etc.)</param>
 568         /// <param name="commandText">The stored procedure name or T-SQL command</param>
 569         /// <returns>A dataset containing the resultset generated by the command</returns>
 570         public static DataSet ExecuteDataset(SqlConnection connection, CommandType commandType, string commandText)
 571         {
 572             // Pass through the call providing null for the set of SqlParameters
 573             return ExecuteDataset(connection, commandType, commandText, (SqlParameter[])null);
 574         }
 575         
 576         /// <summary>
 577         /// Execute a SqlCommand (that returns a resultset) against the specified SqlConnection 
 578         /// using the provided parameters.
 579         /// </summary>
 580         /// <remarks>
 581         /// e.g.:  
 582         ///  DataSet ds = ExecuteDataset(conn, CommandType.StoredProcedure, "GetOrders", new SqlParameter("@prodid", 24));
 583         /// </remarks>
 584         /// <param name="connection">A valid SqlConnection</param>
 585         /// <param name="commandType">The CommandType (stored procedure, text, etc.)</param>
 586         /// <param name="commandText">The stored procedure name or T-SQL command</param>
 587         /// <param name="commandParameters">An array of SqlParamters used to execute the command</param>
 588         /// <returns>A dataset containing the resultset generated by the command</returns>
 589         public static DataSet ExecuteDataset(SqlConnection connection, CommandType commandType, string commandText, params SqlParameter[] commandParameters)
 590         {
 591             if( connection == null ) throw new ArgumentNullException( "connection" );
 592 
 593             // Create a command and prepare it for execution
 594             SqlCommand cmd = new SqlCommand();
 595             bool mustCloseConnection = false;
 596             PrepareCommand(cmd, connection, (SqlTransaction)null, commandType, commandText, commandParameters, out mustCloseConnection );
 597                 
 598             // Create the DataAdapter & DataSet
 599             using( SqlDataAdapter da = new SqlDataAdapter(cmd) )
 600             {
 601                 DataSet ds = new DataSet();
 602 
 603                 // Fill the DataSet using default values for DataTable names, etc
 604                 da.Fill(ds);
 605                 
 606                 // Detach the SqlParameters from the command object, so they can be used again
 607                 cmd.Parameters.Clear();
 608 
 609                 if( mustCloseConnection )
 610                     connection.Close();
 611 
 612                 // Return the dataset
 613                 return ds;
 614             }    
 615         }
 616         
 617         /// <summary>
 618         /// Execute a stored procedure via a SqlCommand (that returns a resultset) against the specified SqlConnection 
 619         /// using the provided parameter values.  This method will query the database to discover the parameters for the 
 620         /// stored procedure (the first time each stored procedure is called), and assign the values based on parameter order.
 621         /// </summary>
 622         /// <remarks>
 623         /// This method provides no access to output parameters or the stored procedure's return value parameter.
 624         /// 
 625         /// e.g.:  
 626         ///  DataSet ds = ExecuteDataset(conn, "GetOrders", 24, 36);
 627         /// </remarks>
 628         /// <param name="connection">A valid SqlConnection</param>
 629         /// <param name="spName">The name of the stored procedure</param>
 630         /// <param name="parameterValues">An array of objects to be assigned as the input values of the stored procedure</param>
 631         /// <returns>A dataset containing the resultset generated by the command</returns>
 632         public static DataSet ExecuteDataset(SqlConnection connection, string spName, params object[] parameterValues)
 633         {
 634             if( connection == null ) throw new ArgumentNullException( "connection" );
 635             if( spName == null || spName.Length == 0 ) throw new ArgumentNullException( "spName" );
 636 
 637             // If we receive parameter values, we need to figure out where they go
 638             if ((parameterValues != null) && (parameterValues.Length > 0)) 
 639             {
 640                 // Pull the parameters for this stored procedure from the parameter cache (or discover them & populate the cache)
 641                 SqlParameter[] commandParameters = SqlHelperParameterCache.GetSpParameterSet(connection, spName);
 642 
 643                 // Assign the provided values to these parameters based on parameter order
 644                 AssignParameterValues(commandParameters, parameterValues);
 645 
 646                 // Call the overload that takes an array of SqlParameters
 647                 return ExecuteDataset(connection, CommandType.StoredProcedure, spName, commandParameters);
 648             }
 649             else 
 650             {
 651                 // Otherwise we can just call the SP without params
 652                 return ExecuteDataset(connection, CommandType.StoredProcedure, spName);
 653             }
 654         }
 655 
 656         /// <summary>
 657         /// Execute a SqlCommand (that returns a resultset and takes no parameters) against the provided SqlTransaction. 
 658         /// </summary>
 659         /// <remarks>
 660         /// e.g.:  
 661         ///  DataSet ds = ExecuteDataset(trans, CommandType.StoredProcedure, "GetOrders");
 662         /// </remarks>
 663         /// <param name="transaction">A valid SqlTransaction</param>
 664         /// <param name="commandType">The CommandType (stored procedure, text, etc.)</param>
 665         /// <param name="commandText">The stored procedure name or T-SQL command</param>
 666         /// <returns>A dataset containing the resultset generated by the command</returns>
 667         public static DataSet ExecuteDataset(SqlTransaction transaction, CommandType commandType, string commandText)
 668         {
 669             // Pass through the call providing null for the set of SqlParameters
 670             return ExecuteDataset(transaction, commandType, commandText, (SqlParameter[])null);
 671         }
 672         
 673         /// <summary>
 674         /// Execute a SqlCommand (that returns a resultset) against the specified SqlTransaction
 675         /// using the provided parameters.
 676         /// </summary>
 677         /// <remarks>
 678         /// e.g.:  
 679         ///  DataSet ds = ExecuteDataset(trans, CommandType.StoredProcedure, "GetOrders", new SqlParameter("@prodid", 24));
 680         /// </remarks>
 681         /// <param name="transaction">A valid SqlTransaction</param>
 682         /// <param name="commandType">The CommandType (stored procedure, text, etc.)</param>
 683         /// <param name="commandText">The stored procedure name or T-SQL command</param>
 684         /// <param name="commandParameters">An array of SqlParamters used to execute the command</param>
 685         /// <returns>A dataset containing the resultset generated by the command</returns>
 686         public static DataSet ExecuteDataset(SqlTransaction transaction, CommandType commandType, string commandText, params SqlParameter[] commandParameters)
 687         {
 688             if( transaction == null ) throw new ArgumentNullException( "transaction" );
 689             if( transaction != null && transaction.Connection == null ) throw new ArgumentException( "The transaction was rollbacked or commited, please provide an open transaction.", "transaction" );
 690 
 691             // Create a command and prepare it for execution
 692             SqlCommand cmd = new SqlCommand();
 693             bool mustCloseConnection = false;
 694             PrepareCommand(cmd, transaction.Connection, transaction, commandType, commandText, commandParameters, out mustCloseConnection );
 695                 
 696             // Create the DataAdapter & DataSet
 697             using( SqlDataAdapter da = new SqlDataAdapter(cmd) )
 698             {
 699                 DataSet ds = new DataSet();
 700 
 701                 // Fill the DataSet using default values for DataTable names, etc
 702                 da.Fill(ds);
 703                 
 704                 // Detach the SqlParameters from the command object, so they can be used again
 705                 cmd.Parameters.Clear();
 706 
 707                 // Return the dataset
 708                 return ds;
 709             }    
 710         }
 711         
 712         /// <summary>
 713         /// Execute a stored procedure via a SqlCommand (that returns a resultset) against the specified 
 714         /// SqlTransaction using the provided parameter values.  This method will query the database to discover the parameters for the 
 715         /// stored procedure (the first time each stored procedure is called), and assign the values based on parameter order.
 716         /// </summary>
 717         /// <remarks>
 718         /// This method provides no access to output parameters or the stored procedure's return value parameter.
 719         /// 
 720         /// e.g.:  
 721         ///  DataSet ds = ExecuteDataset(trans, "GetOrders", 24, 36);
 722         /// </remarks>
 723         /// <param name="transaction">A valid SqlTransaction</param>
 724         /// <param name="spName">The name of the stored procedure</param>
 725         /// <param name="parameterValues">An array of objects to be assigned as the input values of the stored procedure</param>
 726         /// <returns>A dataset containing the resultset generated by the command</returns>
 727         public static DataSet ExecuteDataset(SqlTransaction transaction, string spName, params object[] parameterValues)
 728         {
 729             if( transaction == null ) throw new ArgumentNullException( "transaction" );
 730             if( transaction != null && transaction.Connection == null ) throw new ArgumentException( "The transaction was rollbacked or commited, please provide an open transaction.", "transaction" );
 731             if( spName == null || spName.Length == 0 ) throw new ArgumentNullException( "spName" );
 732             
 733             // If we receive parameter values, we need to figure out where they go
 734             if ((parameterValues != null) && (parameterValues.Length > 0)) 
 735             {
 736                 // Pull the parameters for this stored procedure from the parameter cache (or discover them & populate the cache)
 737                 SqlParameter[] commandParameters = SqlHelperParameterCache.GetSpParameterSet(transaction.Connection, spName);
 738 
 739                 // Assign the provided values to these parameters based on parameter order
 740                 AssignParameterValues(commandParameters, parameterValues);
 741 
 742                 // Call the overload that takes an array of SqlParameters
 743                 return ExecuteDataset(transaction, CommandType.StoredProcedure, spName, commandParameters);
 744             }
 745             else 
 746             {
 747                 // Otherwise we can just call the SP without params
 748                 return ExecuteDataset(transaction, CommandType.StoredProcedure, spName);
 749             }
 750         }
 751 
 752         #endregion ExecuteDataset
 753         
 754         #region ExecuteReader
 755 
 756         /// <summary>
 757         /// This enum is used to indicate whether the connection was provided by the caller, or created by SqlHelper, so that
 758         /// we can set the appropriate CommandBehavior when calling ExecuteReader()
 759         /// </summary>
 760         private enum SqlConnectionOwnership    
 761         {
 762             /// <summary>Connection is owned and managed by SqlHelper</summary>
 763             Internal, 
 764             /// <summary>Connection is owned and managed by the caller</summary>
 765             External
 766         }
 767 
 768         /// <summary>
 769         /// Create and prepare a SqlCommand, and call ExecuteReader with the appropriate CommandBehavior.
 770         /// </summary>
 771         /// <remarks>
 772         /// If we created and opened the connection, we want the connection to be closed when the DataReader is closed.
 773         /// 
 774         /// If the caller provided the connection, we want to leave it to them to manage.
 775         /// </remarks>
 776         /// <param name="connection">A valid SqlConnection, on which to execute this command</param>
 777         /// <param name="transaction">A valid SqlTransaction, or 'null'</param>
 778         /// <param name="commandType">The CommandType (stored procedure, text, etc.)</param>
 779         /// <param name="commandText">The stored procedure name or T-SQL command</param>
 780         /// <param name="commandParameters">An array of SqlParameters to be associated with the command or 'null' if no parameters are required</param>
 781         /// <param name="connectionOwnership">Indicates whether the connection parameter was provided by the caller, or created by SqlHelper</param>
 782         /// <returns>SqlDataReader containing the results of the command</returns>
 783         private static SqlDataReader ExecuteReader(SqlConnection connection, SqlTransaction transaction, CommandType commandType, string commandText, SqlParameter[] commandParameters, SqlConnectionOwnership connectionOwnership)
 784         {    
 785             if( connection == null ) throw new ArgumentNullException( "connection" );
 786 
 787             bool mustCloseConnection = false;
 788             // Create a command and prepare it for execution
 789             SqlCommand cmd = new SqlCommand();
 790             try
 791             {
 792                 PrepareCommand(cmd, connection, transaction, commandType, commandText, commandParameters, out mustCloseConnection );
 793             
 794                 // Create a reader
 795                 SqlDataReader dataReader;
 796 
 797                 // Call ExecuteReader with the appropriate CommandBehavior
 798                 if (connectionOwnership == SqlConnectionOwnership.External)
 799                 {
 800                     dataReader = cmd.ExecuteReader();
 801                 }
 802                 else
 803                 {
 804                     dataReader = cmd.ExecuteReader(CommandBehavior.CloseConnection);
 805                 }
 806             
 807                 // Detach the SqlParameters from the command object, so they can be used again.
 808                 // HACK: There is a problem here, the output parameter values are fletched 
 809                 // when the reader is closed, so if the parameters are detached from the command
 810                 // then the SqlReader can磘 set its values. 
 811                 // When this happen, the parameters can磘 be used again in other command.
 812                 bool canClear = true;
 813                 foreach(SqlParameter commandParameter in cmd.Parameters)
 814                 {
 815                     if (commandParameter.Direction != ParameterDirection.Input)
 816                         canClear = false;
 817                 }
 818             
 819                 if (canClear)
 820                 {
 821                     cmd.Parameters.Clear();
 822                 }
 823 
 824                 return dataReader;
 825             }
 826             catch
 827             {
 828                 if( mustCloseConnection )
 829                     connection.Close();
 830                 throw;
 831             }
 832         }
 833 
 834         /// <summary>
 835         /// Execute a SqlCommand (that returns a resultset and takes no parameters) against the database specified in 
 836         /// the connection string. 
 837         /// </summary>
 838         /// <remarks>
 839         /// e.g.:  
 840         ///  SqlDataReader dr = ExecuteReader(connString, CommandType.StoredProcedure, "GetOrders");
 841         /// </remarks>
 842         /// <param name="connectionString">A valid connection string for a SqlConnection</param>
 843         /// <param name="commandType">The CommandType (stored procedure, text, etc.)</param>
 844         /// <param name="commandText">The stored procedure name or T-SQL command</param>
 845         /// <returns>A SqlDataReader containing the resultset generated by the command</returns>
 846         public static SqlDataReader ExecuteReader(string connectionString, CommandType commandType, string commandText)
 847         {
 848             // Pass through the call providing null for the set of SqlParameters
 849             return ExecuteReader(connectionString, commandType, commandText, (SqlParameter[])null);
 850         }
 851 
 852         /// <summary>
 853         /// Execute a SqlCommand (that returns a resultset) against the database specified in the connection string 
 854         /// using the provided parameters.
 855         /// </summary>
 856         /// <remarks>
 857         /// e.g.:  
 858         ///  SqlDataReader dr = ExecuteReader(connString, CommandType.StoredProcedure, "GetOrders", new SqlParameter("@prodid", 24));
 859         /// </remarks>
 860         /// <param name="connectionString">A valid connection string for a SqlConnection</param>
 861         /// <param name="commandType">The CommandType (stored procedure, text, etc.)</param>
 862         /// <param name="commandText">The stored procedure name or T-SQL command</param>
 863         /// <param name="commandParameters">An array of SqlParamters used to execute the command</param>
 864         /// <returns>A SqlDataReader containing the resultset generated by the command</returns>
 865         public static SqlDataReader ExecuteReader(string connectionString, CommandType commandType, string commandText, params SqlParameter[] commandParameters)
 866         {
 867             if( connectionString == null || connectionString.Length == 0 ) throw new ArgumentNullException( "connectionString" );
 868             SqlConnection connection = null;
 869             try
 870             {
 871                 connection = new SqlConnection(connectionString);
 872                 connection.Open();
 873 
 874                 // Call the private overload that takes an internally owned connection in place of the connection string
 875                 return ExecuteReader(connection, null, commandType, commandText, commandParameters,SqlConnectionOwnership.Internal);
 876             }
 877             catch
 878             {
 879                 // If we fail to return the SqlDatReader, we need to close the connection ourselves
 880                 if( connection != null ) connection.Close();
 881                 throw;
 882             }
 883             
 884         }
 885 
 886         /// <summary>
 887         /// Execute a stored procedure via a SqlCommand (that returns a resultset) against the database specified in 
 888         /// the connection string using the provided parameter values.  This method will query the database to discover the parameters for the 
 889         /// stored procedure (the first time each stored procedure is called), and assign the values based on parameter order.
 890         /// </summary>
 891         /// <remarks>
 892         /// This method provides no access to output parameters or the stored procedure's return value parameter.
 893         /// 
 894         /// e.g.:  
 895         ///  SqlDataReader dr = ExecuteReader(connString, "GetOrders", 24, 36);
 896         /// </remarks>
 897         /// <param name="connectionString">A valid connection string for a SqlConnection</param>
 898         /// <param name="spName">The name of the stored procedure</param>
 899         /// <param name="parameterValues">An array of objects to be assigned as the input values of the stored procedure</param>
 900         /// <returns>A SqlDataReader containing the resultset generated by the command</returns>
 901         public static SqlDataReader ExecuteReader(string connectionString, string spName, params object[] parameterValues)
 902         {
 903             if( connectionString == null || connectionString.Length == 0 ) throw new ArgumentNullException( "connectionString" );
 904             if( spName == null || spName.Length == 0 ) throw new ArgumentNullException( "spName" );
 905             
 906             // If we receive parameter values, we need to figure out where they go
 907             if ((parameterValues != null) && (parameterValues.Length > 0)) 
 908             {
 909                 SqlParameter[] commandParameters = SqlHelperParameterCache.GetSpParameterSet(connectionString, spName);
 910 
 911                 AssignParameterValues(commandParameters, parameterValues);
 912 
 913                 return ExecuteReader(connectionString, CommandType.StoredProcedure, spName, commandParameters);
 914             }
 915             else 
 916             {
 917                 // Otherwise we can just call the SP without params
 918                 return ExecuteReader(connectionString, CommandType.StoredProcedure, spName);
 919             }
 920         }
 921 
 922         /// <summary>
 923         /// Execute a SqlCommand (that returns a resultset and takes no parameters) against the provided SqlConnection. 
 924         /// </summary>
 925         /// <remarks>
 926         /// e.g.:  
 927         ///  SqlDataReader dr = ExecuteReader(conn, CommandType.StoredProcedure, "GetOrders");
 928         /// </remarks>
 929         /// <param name="connection">A valid SqlConnection</param>
 930         /// <param name="commandType">The CommandType (stored procedure, text, etc.)</param>
 931         /// <param name="commandText">The stored procedure name or T-SQL command</param>
 932         /// <returns>A SqlDataReader containing the resultset generated by the command</returns>
 933         public static SqlDataReader ExecuteReader(SqlConnection connection, CommandType commandType, string commandText)
 934         {
 935             // Pass through the call providing null for the set of SqlParameters
 936             return ExecuteReader(connection, commandType, commandText, (SqlParameter[])null);
 937         }
 938 
 939         /// <summary>
 940         /// Execute a SqlCommand (that returns a resultset) against the specified SqlConnection 
 941         /// using the provided parameters.
 942         /// </summary>
 943         /// <remarks>
 944         /// e.g.:  
 945         ///  SqlDataReader dr = ExecuteReader(conn, CommandType.StoredProcedure, "GetOrders", new SqlParameter("@prodid", 24));
 946         /// </remarks>
 947         /// <param name="connection">A valid SqlConnection</param>
 948         /// <param name="commandType">The CommandType (stored procedure, text, etc.)</param>
 949         /// <param name="commandText">The stored procedure name or T-SQL command</param>
 950         /// <param name="commandParameters">An array of SqlParamters used to execute the command</param>
 951         /// <returns>A SqlDataReader containing the resultset generated by the command</returns>
 952         public static SqlDataReader ExecuteReader(SqlConnection connection, CommandType commandType, string commandText, params SqlParameter[] commandParameters)
 953         {
 954             // Pass through the call to the private overload using a null transaction value and an externally owned connection
 955             return ExecuteReader(connection, (SqlTransaction)null, commandType, commandText, commandParameters, SqlConnectionOwnership.External);
 956         }
 957 
 958         /// <summary>
 959         /// Execute a stored procedure via a SqlCommand (that returns a resultset) against the specified SqlConnection 
 960         /// using the provided parameter values.  This method will query the database to discover the parameters for the 
 961         /// stored procedure (the first time each stored procedure is called), and assign the values based on parameter order.
 962         /// </summary>
 963         /// <remarks>
 964         /// This method provides no access to output parameters or the stored procedure's return value parameter.
 965         /// 
 966         /// e.g.:  
 967         ///  SqlDataReader dr = ExecuteReader(conn, "GetOrders", 24, 36);
 968         /// </remarks>
 969         /// <param name="connection">A valid SqlConnection</param>
 970         /// <param name="spName">The name of the stored procedure</param>
 971         /// <param name="parameterValues">An array of objects to be assigned as the input values of the stored procedure</param>
 972         /// <returns>A SqlDataReader containing the resultset generated by the command</returns>
 973         public static SqlDataReader ExecuteReader(SqlConnection connection, string spName, params object[] parameterValues)
 974         {
 975             if( connection == null ) throw new ArgumentNullException( "connection" );
 976             if( spName == null || spName.Length == 0 ) throw new ArgumentNullException( "spName" );
 977 
 978             // If we receive parameter values, we need to figure out where they go
 979             if ((parameterValues != null) && (parameterValues.Length > 0)) 
 980             {
 981                 SqlParameter[] commandParameters = SqlHelperParameterCache.GetSpParameterSet(connection, spName);
 982 
 983                 AssignParameterValues(commandParameters, parameterValues);
 984 
 985                 return ExecuteReader(connection, CommandType.StoredProcedure, spName, commandParameters);
 986             }
 987             else 
 988             {
 989                 // Otherwise we can just call the SP without params
 990                 return ExecuteReader(connection, CommandType.StoredProcedure, spName);
 991             }
 992         }
 993 
 994         /// <summary>
 995         /// Execute a SqlCommand (that returns a resultset and takes no parameters) against the provided SqlTransaction. 
 996         /// </summary>
 997         /// <remarks>
 998         /// e.g.:  
 999         ///  SqlDataReader dr = ExecuteReader(trans, CommandType.StoredProcedure, "GetOrders");
1000         /// </remarks>
1001         /// <param name="transaction">A valid SqlTransaction</param>
1002         /// <param name="commandType">The CommandType (stored procedure, text, etc.)</param>
1003         /// <param name="commandText">The stored procedure name or T-SQL command</param>
1004         /// <returns>A SqlDataReader containing the resultset generated by the command</returns>
1005         public static SqlDataReader ExecuteReader(SqlTransaction transaction, CommandType commandType, string commandText)
1006         {
1007             // Pass through the call providing null for the set of SqlParameters
1008             return ExecuteReader(transaction, commandType, commandText, (SqlParameter[])null);
1009         }
1010 
1011         /// <summary>
1012         /// Execute a SqlCommand (that returns a resultset) against the specified SqlTransaction
1013         /// using the provided parameters.
1014         /// </summary>
1015         /// <remarks>
1016         /// e.g.:  
1017         ///   SqlDataReader dr = ExecuteReader(trans, CommandType.StoredProcedure, "GetOrders", new SqlParameter("@prodid", 24));
1018         /// </remarks>
1019         /// <param name="transaction">A valid SqlTransaction</param>
1020         /// <param name="commandType">The CommandType (stored procedure, text, etc.)</param>
1021         /// <param name="commandText">The stored procedure name or T-SQL command</param>
1022         /// <param name="commandParameters">An array of SqlParamters used to execute the command</param>
1023         /// <returns>A SqlDataReader containing the resultset generated by the command</returns>
1024         public static SqlDataReader ExecuteReader(SqlTransaction transaction, CommandType commandType, string commandText, params SqlParameter[] commandParameters)
1025         {
1026             if( transaction == null ) throw new ArgumentNullException( "transaction" );
1027             if( transaction != null && transaction.Connection == null ) throw new ArgumentException( "The transaction was rollbacked or commited, please provide an open transaction.", "transaction" );
1028 
1029             // Pass through to private overload, indicating that the connection is owned by the caller
1030             return ExecuteReader(transaction.Connection, transaction, commandType, commandText, commandParameters, SqlConnectionOwnership.External);
1031         }
1032 
1033         /// <summary>
1034         /// Execute a stored procedure via a SqlCommand (that returns a resultset) against the specified
1035         /// SqlTransaction using the provided parameter values.  This method will query the database to discover the parameters for the 
1036         /// stored procedure (the first time each stored procedure is called), and assign the values based on parameter order.
1037         /// </summary>
1038         /// <remarks>
1039         /// This method provides no access to output parameters or the stored procedure's return value parameter.
1040         /// 
1041         /// e.g.:  
1042         ///  SqlDataReader dr = ExecuteReader(trans, "GetOrders", 24, 36);
1043         /// </remarks>
1044         /// <param name="transaction">A valid SqlTransaction</param>
1045         /// <param name="spName">The name of the stored procedure</param>
1046         /// <param name="parameterValues">An array of objects to be assigned as the input values of the stored procedure</param>
1047         /// <returns>A SqlDataReader containing the resultset generated by the command</returns>
1048         public static SqlDataReader ExecuteReader(SqlTransaction transaction, string spName, params object[] parameterValues)
1049         {
1050             if( transaction == null ) throw new ArgumentNullException( "transaction" );
1051             if( transaction != null && transaction.Connection == null ) throw new ArgumentException( "The transaction was rollbacked or commited, please provide an open transaction.", "transaction" );
1052             if( spName == null || spName.Length == 0 ) throw new ArgumentNullException( "spName" );
1053 
1054             // If we receive parameter values, we need to figure out where they go
1055             if ((parameterValues != null) && (parameterValues.Length > 0)) 
1056             {
1057                 SqlParameter[] commandParameters = SqlHelperParameterCache.GetSpParameterSet(transaction.Connection, spName);
1058 
1059                 AssignParameterValues(commandParameters, parameterValues);
1060 
1061                 return ExecuteReader(transaction, CommandType.StoredProcedure, spName, commandParameters);
1062             }
1063             else 
1064             {
1065                 // Otherwise we can just call the SP without params
1066                 return ExecuteReader(transaction, CommandType.StoredProcedure, spName);
1067             }
1068         }
1069 
1070         #endregion ExecuteReader
1071 
1072         #region ExecuteScalar
1073         
1074         /// <summary>
1075         /// Execute a SqlCommand (that returns a 1x1 resultset and takes no parameters) against the database specified in 
1076         /// the connection string. 
1077         /// </summary>
1078         /// <remarks>
1079         /// e.g.:  
1080         ///  int orderCount = (int)ExecuteScalar(connString, CommandType.StoredProcedure, "GetOrderCount");
1081         /// </remarks>
1082         /// <param name="connectionString">A valid connection string for a SqlConnection</param>
1083         /// <param name="commandType">The CommandType (stored procedure, text, etc.)</param>
1084         /// <param name="commandText">The stored procedure name or T-SQL command</param>
1085         /// <returns>An object containing the value in the 1x1 resultset generated by the command</returns>
1086         public static object ExecuteScalar(string connectionString, CommandType commandType, string commandText)
1087         {
1088             // Pass through the call providing null for the set of SqlParameters
1089             return ExecuteScalar(connectionString, commandType, commandText, (SqlParameter[])null);
1090         }
1091 
1092         /// <summary>
1093         /// Execute a SqlCommand (that returns a 1x1 resultset) against the database specified in the connection string 
1094         /// using the provided parameters.
1095         /// </summary>
1096         /// <remarks>
1097         /// e.g.:  
1098         ///  int orderCount = (int)ExecuteScalar(connString, CommandType.StoredProcedure, "GetOrderCount", new SqlParameter("@prodid", 24));
1099         /// </remarks>
1100         /// <param name="connectionString">A valid connection string for a SqlConnection</param>
1101         /// <param name="commandType">The CommandType (stored procedure, text, etc.)</param>
1102         /// <param name="commandText">The stored procedure name or T-SQL command</param>
1103         /// <param name="commandParameters">An array of SqlParamters used to execute the command</param>
1104         /// <returns>An object containing the value in the 1x1 resultset generated by the command</returns>
1105         public static object ExecuteScalar(string connectionString, CommandType commandType, string commandText, params SqlParameter[] commandParameters)
1106         {
1107             if( connectionString == null || connectionString.Length == 0 ) throw new ArgumentNullException( "connectionString" );
1108             // Create & open a SqlConnection, and dispose of it after we are done
1109             using (SqlConnection connection = new SqlConnection(connectionString))
1110             {
1111                 connection.Open();
1112 
1113                 // Call the overload that takes a connection in place of the connection string
1114                 return ExecuteScalar(connection, commandType, commandText, commandParameters);
1115             }
1116         }
1117 
1118         /// <summary>
1119         /// Execute a stored procedure via a SqlCommand (that returns a 1x1 resultset) against the database specified in 
1120         /// the connection string using the provided parameter values.  This method will query the database to discover the parameters for the 
1121         /// stored procedure (the first time each stored procedure is called), and assign the values based on parameter order.
1122         /// </summary>
1123         /// <remarks>
1124         /// This method provides no access to output parameters or the stored procedure's return value parameter.
1125         /// 
1126         /// e.g.:  
1127         ///  int orderCount = (int)ExecuteScalar(connString, "GetOrderCount", 24, 36);
1128         /// </remarks>
1129         /// <param name="connectionString">A valid connection string for a SqlConnection</param>
1130         /// <param name="spName">The name of the stored procedure</param>
1131         /// <param name="parameterValues">An array of objects to be assigned as the input values of the stored procedure</param>
1132         /// <returns>An object containing the value in the 1x1 resultset generated by the command</returns>
1133         public static object ExecuteScalar(string connectionString, string spName, params object[] parameterValues)
1134         {
1135             if( connectionString == null || connectionString.Length == 0 ) throw new ArgumentNullException( "connectionString" );
1136             if( spName == null || spName.Length == 0 ) throw new ArgumentNullException( "spName" );
1137             
1138             // If we receive parameter values, we need to figure out where they go
1139             if ((parameterValues != null) && (parameterValues.Length > 0)) 
1140             {
1141                 // Pull the parameters for this stored procedure from the parameter cache (or discover them & populate the cache)
1142                 SqlParameter[] commandParameters = SqlHelperParameterCache.GetSpParameterSet(connectionString, spName);
1143 
1144                 // Assign the provided values to these parameters based on parameter order
1145                 AssignParameterValues(commandParameters, parameterValues);
1146 
1147                 // Call the overload that takes an array of SqlParameters
1148                 return ExecuteScalar(connectionString, CommandType.StoredProcedure, spName, commandParameters);
1149             }
1150             else 
1151             {
1152                 // Otherwise we can just call the SP without params
1153                 return ExecuteScalar(connectionString, CommandType.StoredProcedure, spName);
1154             }
1155         }
1156 
1157         /// <summary>
1158         /// Execute a SqlCommand (that returns a 1x1 resultset and takes no parameters) against the provided SqlConnection. 
1159         /// </summary>
1160         /// <remarks>
1161         /// e.g.:  
1162         ///  int orderCount = (int)ExecuteScalar(conn, CommandType.StoredProcedure, "GetOrderCount");
1163         /// </remarks>
1164         /// <param name="connection">A valid SqlConnection</param>
1165         /// <param name="commandType">The CommandType (stored procedure, text, etc.)</param>
1166         /// <param name="commandText">The stored procedure name or T-SQL command</param>
1167         /// <returns>An object containing the value in the 1x1 resultset generated by the command</returns>
1168         public static object ExecuteScalar(SqlConnection connection, CommandType commandType, string commandText)
1169         {
1170             // Pass through the call providing null for the set of SqlParameters
1171             return ExecuteScalar(connection, commandType, commandText, (SqlParameter[])null);
1172         }
1173 
1174         /// <summary>
1175         /// Execute a SqlCommand (that returns a 1x1 resultset) against the specified SqlConnection 
1176         /// using the provided parameters.
1177         /// </summary>
1178         /// <remarks>
1179         /// e.g.:  
1180         ///  int orderCount = (int)ExecuteScalar(conn, CommandType.StoredProcedure, "GetOrderCount", new SqlParameter("@prodid", 24));
1181         /// </remarks>
1182         /// <param name="connection">A valid SqlConnection</param>
1183         /// <param name="commandType">The CommandType (stored procedure, text, etc.)</param>
1184         /// <param name="commandText">The stored procedure name or T-SQL command</param>
1185         /// <param name="commandParameters">An array of SqlParamters used to execute the command</param>
1186         /// <returns>An object containing the value in the 1x1 resultset generated by the command</returns>
1187         public static object ExecuteScalar(SqlConnection connection, CommandType commandType, string commandText, params SqlParameter[] commandParameters)
1188         {
1189             if( connection == null ) throw new ArgumentNullException( "connection" );
1190 
1191             // Create a command and prepare it for execution
1192             SqlCommand cmd = new SqlCommand();
1193 
1194             bool mustCloseConnection = false;
1195             PrepareCommand(cmd, connection, (SqlTransaction)null, commandType, commandText, commandParameters, out mustCloseConnection );
1196                 
1197             // Execute the command & return the results
1198             object retval = cmd.ExecuteScalar();
1199                 
1200             // Detach the SqlParameters from the command object, so they can be used again
1201             cmd.Parameters.Clear();
1202 
1203             if( mustCloseConnection )
1204                 connection.Close();
1205 
1206             return retval;
1207         }
1208 
1209         /// <summary>
1210         /// Execute a stored procedure via a SqlCommand (that returns a 1x1 resultset) against the specified SqlConnection 
1211         /// using the provided parameter values.  This method will query the database to discover the parameters for the 
1212         /// stored procedure (the first time each stored procedure is called), and assign the values based on parameter order.
1213         /// </summary>
1214         /// <remarks>
1215         /// This method provides no access to output parameters or the stored procedure's return value parameter.
1216         /// 
1217         /// e.g.:  
1218         ///  int orderCount = (int)ExecuteScalar(conn, "GetOrderCount", 24, 36);
1219         /// </remarks>
1220         /// <param name="connection">A valid SqlConnection</param>
1221         /// <param name="spName">The name of the stored procedure</param>
1222         /// <param name="parameterValues">An array of objects to be assigned as the input values of the stored procedure</param>
1223         /// <returns>An object containing the value in the 1x1 resultset generated by the command</returns>
1224         public static object ExecuteScalar(SqlConnection connection, string spName, params object[] parameterValues)
1225         {
1226             if( connection == null ) throw new ArgumentNullException( "connection" );
1227             if( spName == null || spName.Length == 0 ) throw new ArgumentNullException( "spName" );
1228 
1229             // If we receive parameter values, we need to figure out where they go
1230             if ((parameterValues != null) && (parameterValues.Length > 0)) 
1231             {
1232                 // Pull the parameters for this stored procedure from the parameter cache (or discover them & populate the cache)
1233                 SqlParameter[] commandParameters = SqlHelperParameterCache.GetSpParameterSet(connection, spName);
1234 
1235                 // Assign the provided values to these parameters based on parameter order
1236                 AssignParameterValues(commandParameters, parameterValues);
1237 
1238                 // Call the overload that takes an array of SqlParameters
1239                 return ExecuteScalar(connection, CommandType.StoredProcedure, spName, commandParameters);
1240             }
1241             else 
1242             {
1243                 // Otherwise we can just call the SP without params
1244                 return ExecuteScalar(connection, CommandType.StoredProcedure, spName);
1245             }
1246         }
1247 
1248         /// <summary>
1249         /// Execute a SqlCommand (that returns a 1x1 resultset and takes no parameters) against the provided SqlTransaction. 
1250         /// </summary>
1251         /// <remarks>
1252         /// e.g.:  
1253         ///  int orderCount = (int)ExecuteScalar(trans, CommandType.StoredProcedure, "GetOrderCount");
1254         /// </remarks>
1255         /// <param name="transaction">A valid SqlTransaction</param>
1256         /// <param name="commandType">The CommandType (stored procedure, text, etc.)</param>
1257         /// <param name="commandText">The stored procedure name or T-SQL command</param>
1258         /// <returns>An object containing the value in the 1x1 resultset generated by the command</returns>
1259         public static object ExecuteScalar(SqlTransaction transaction, CommandType commandType, string commandText)
1260         {
1261             // Pass through the call providing null for the set of SqlParameters
1262             return ExecuteScalar(transaction, commandType, commandText, (SqlParameter[])null);
1263         }
1264 
1265         /// <summary>
1266         /// Execute a SqlCommand (that returns a 1x1 resultset) against the specified SqlTransaction
1267         /// using the provided parameters.
1268         /// </summary>
1269         /// <remarks>
1270         /// e.g.:  
1271         ///  int orderCount = (int)ExecuteScalar(trans, CommandType.StoredProcedure, "GetOrderCount", new SqlParameter("@prodid", 24));
1272         /// </remarks>
1273         /// <param name="transaction">A valid SqlTransaction</param>
1274         /// <param name="commandType">The CommandType (stored procedure, text, etc.)</param>
1275         /// <param name="commandText">The stored procedure name or T-SQL command</param>
1276         /// <param name="commandParameters">An array of SqlParamters used to execute the command</param>
1277         /// <returns>An object containing the value in the 1x1 resultset generated by the command</returns>
1278         public static object ExecuteScalar(SqlTransaction transaction, CommandType commandType, string commandText, params SqlParameter[] commandParameters)
1279         {
1280             if( transaction == null ) throw new ArgumentNullException( "transaction" );
1281             if( transaction != null && transaction.Connection == null ) throw new ArgumentException( "The transaction was rollbacked or commited, please provide an open transaction.", "transaction" );
1282 
1283             // Create a command and prepare it for execution
1284             SqlCommand cmd = new SqlCommand();
1285             bool mustCloseConnection = false;
1286             PrepareCommand(cmd, transaction.Connection, transaction, commandType, commandText, commandParameters, out mustCloseConnection );
1287                 
1288             // Execute the command & return the results
1289             object retval = cmd.ExecuteScalar();
1290                 
1291             // Detach the SqlParameters from the command object, so they can be used again
1292             cmd.Parameters.Clear();
1293             return retval;
1294         }
1295 
1296         /// <summary>
1297         /// Execute a stored procedure via a SqlCommand (that returns a 1x1 resultset) against the specified
1298         /// SqlTransaction using the provided parameter values.  This method will query the database to discover the parameters for the 
1299         /// stored procedure (the first time each stored procedure is called), and assign the values based on parameter order.
1300         /// </summary>
1301         /// <remarks>
1302         /// This method provides no access to output parameters or the stored procedure's return value parameter.
1303         /// 
1304         /// e.g.:  
1305         ///  int orderCount = (int)ExecuteScalar(trans, "GetOrderCount", 24, 36);
1306         /// </remarks>
1307         /// <param name="transaction">A valid SqlTransaction</param>
1308         /// <param name="spName">The name of the stored procedure</param>
1309         /// <param name="parameterValues">An array of objects to be assigned as the input values of the stored procedure</param>
1310         /// <returns>An object containing the value in the 1x1 resultset generated by the command</returns>
1311         public static object ExecuteScalar(SqlTransaction transaction, string spName, params object[] parameterValues)
1312         {
1313             if( transaction == null ) throw new ArgumentNullException( "transaction" );
1314             if( transaction != null && transaction.Connection == null ) throw new ArgumentException( "The transaction was rollbacked or commited, please provide an open transaction.", "transaction" );
1315             if( spName == null || spName.Length == 0 ) throw new ArgumentNullException( "spName" );
1316 
1317             // If we receive parameter values, we need to figure out where they go
1318             if ((parameterValues != null) && (parameterValues.Length > 0)) 
1319             {
1320                 // PPull the parameters for this stored procedure from the parameter cache (or discover them & populate the cache)
1321                 SqlParameter[] commandParameters = SqlHelperParameterCache.GetSpParameterSet(transaction.Connection, spName);
1322 
1323                 // Assign the provided values to these parameters based on parameter order
1324                 AssignParameterValues(commandParameters, parameterValues);
1325 
1326                 // Call the overload that takes an array of SqlParameters
1327                 return ExecuteScalar(transaction, CommandType.StoredProcedure, spName, commandParameters);
1328             }
1329             else 
1330             {
1331                 // Otherwise we can just call the SP without params
1332                 return ExecuteScalar(transaction, CommandType.StoredProcedure, spName);
1333             }
1334         }
1335 
1336         #endregion ExecuteScalar    
1337 
1338         #region ExecuteXmlReader
1339         /// <summary>
1340         /// Execute a SqlCommand (that returns a resultset and takes no parameters) against the provided SqlConnection. 
1341         /// </summary>
1342         /// <remarks>
1343         /// e.g.:  
1344         ///  XmlReader r = ExecuteXmlReader(conn, CommandType.StoredProcedure, "GetOrders");
1345         /// </remarks>
1346         /// <param name="connection">A valid SqlConnection</param>
1347         /// <param name="commandType">The CommandType (stored procedure, text, etc.)</param>
1348         /// <param name="commandText">The stored procedure name or T-SQL command using "FOR XML AUTO"</param>
1349         /// <returns>An XmlReader containing the resultset generated by the command</returns>
1350         public static XmlReader ExecuteXmlReader(SqlConnection connection, CommandType commandType, string commandText)
1351         {
1352             // Pass through the call providing null for the set of SqlParameters
1353             return ExecuteXmlReader(connection, commandType, commandText, (SqlParameter[])null);
1354         }
1355 
1356         /// <summary>
1357         /// Execute a SqlCommand (that returns a resultset) against the specified SqlConnection 
1358         /// using the provided parameters.
1359         /// </summary>
1360         /// <remarks>
1361         /// e.g.:  
1362         ///  XmlReader r = ExecuteXmlReader(conn, CommandType.StoredProcedure, "GetOrders", new SqlParameter("@prodid", 24));
1363         /// </remarks>
1364         /// <param name="connection">A valid SqlConnection</param>
1365         /// <param name="commandType">The CommandType (stored procedure, text, etc.)</param>
1366         /// <param name="commandText">The stored procedure name or T-SQL command using "FOR XML AUTO"</param>
1367         /// <param name="commandParameters">An array of SqlParamters used to execute the command</param>
1368         /// <returns>An XmlReader containing the resultset generated by the command</returns>
1369         public static XmlReader ExecuteXmlReader(SqlConnection connection, CommandType commandType, string commandText, params SqlParameter[] commandParameters)
1370         {
1371             if( connection == null ) throw new ArgumentNullException( "connection" );
1372 
1373             bool mustCloseConnection = false;
1374             // Create a command and prepare it for execution
1375             SqlCommand cmd = new SqlCommand();
1376             try
1377             {
1378                 PrepareCommand(cmd, connection, (SqlTransaction)null, commandType, commandText, commandParameters, out mustCloseConnection );
1379             
1380                 // Create the DataAdapter & DataSet
1381                 XmlReader retval = cmd.ExecuteXmlReader();
1382             
1383                 // Detach the SqlParameters from the command object, so they can be used again
1384                 cmd.Parameters.Clear();
1385 
1386                 return retval;
1387             }
1388             catch
1389             {    
1390                 if( mustCloseConnection )
1391                     connection.Close();
1392                 throw;
1393             }
1394         }
1395 
1396         /// <summary>
1397         /// Execute a stored procedure via a SqlCommand (that returns a resultset) against the specified SqlConnection 
1398         /// using the provided parameter values.  This method will query the database to discover the parameters for the 
1399         /// stored procedure (the first time each stored procedure is called), and assign the values based on parameter order.
1400         /// </summary>
1401         /// <remarks>
1402         /// This method provides no access to output parameters or the stored procedure's return value parameter.
1403         /// 
1404         /// e.g.:  
1405         ///  XmlReader r = ExecuteXmlReader(conn, "GetOrders", 24, 36);
1406         /// </remarks>
1407         /// <param name="connection">A valid SqlConnection</param>
1408         /// <param name="spName">The name of the stored procedure using "FOR XML AUTO"</param>
1409         /// <param name="parameterValues">An array of objects to be assigned as the input values of the stored procedure</param>
1410         /// <returns>An XmlReader containing the resultset generated by the command</returns>
1411         public static XmlReader ExecuteXmlReader(SqlConnection connection, string spName, params object[] parameterValues)
1412         {
1413             if( connection == null ) throw new ArgumentNullException( "connection" );
1414             if( spName == null || spName.Length == 0 ) throw new ArgumentNullException( "spName" );
1415 
1416             // If we receive parameter values, we need to figure out where they go
1417             if ((parameterValues != null) && (parameterValues.Length > 0)) 
1418             {
1419                 // Pull the parameters for this stored procedure from the parameter cache (or discover them & populate the cache)
1420                 SqlParameter[] commandParameters = SqlHelperParameterCache.GetSpParameterSet(connection, spName);
1421 
1422                 // Assign the provided values to these parameters based on parameter order
1423                 AssignParameterValues(commandParameters, parameterValues);
1424 
1425                 // Call the overload that takes an array of SqlParameters
1426                 return ExecuteXmlReader(connection, CommandType.StoredProcedure, spName, commandParameters);
1427             }
1428             else 
1429             {
1430                 // Otherwise we can just call the SP without params
1431                 return ExecuteXmlReader(connection, CommandType.StoredProcedure, spName);
1432             }
1433         }
1434 
1435         /// <summary>
1436         /// Execute a SqlCommand (that returns a resultset and takes no parameters) against the provided SqlTransaction. 
1437         /// </summary>
1438         /// <remarks>
1439         /// e.g.:  
1440         ///  XmlReader r = ExecuteXmlReader(trans, CommandType.StoredProcedure, "GetOrders");
1441         /// </remarks>
1442         /// <param name="transaction">A valid SqlTransaction</param>
1443         /// <param name="commandType">The CommandType (stored procedure, text, etc.)</param>
1444         /// <param name="commandText">The stored procedure name or T-SQL command using "FOR XML AUTO"</param>
1445         /// <returns>An XmlReader containing the resultset generated by the command</returns>
1446         public static XmlReader ExecuteXmlReader(SqlTransaction transaction, CommandType commandType, string commandText)
1447         {
1448             // Pass through the call providing null for the set of SqlParameters
1449             return ExecuteXmlReader(transaction, commandType, commandText, (SqlParameter[])null);
1450         }
1451 
1452         /// <summary>
1453         /// Execute a SqlCommand (that returns a resultset) against the specified SqlTransaction
1454         /// using the provided parameters.
1455         /// </summary>
1456         /// <remarks>
1457         /// e.g.:  
1458         ///  XmlReader r = ExecuteXmlReader(trans, CommandType.StoredProcedure, "GetOrders", new SqlParameter("@prodid", 24));
1459         /// </remarks>
1460         /// <param name="transaction">A valid SqlTransaction</param>
1461         /// <param name="commandType">The CommandType (stored procedure, text, etc.)</param>
1462         /// <param name="commandText">The stored procedure name or T-SQL command using "FOR XML AUTO"</param>
1463         /// <param name="commandParameters">An array of SqlParamters used to execute the command</param>
1464         /// <returns>An XmlReader containing the resultset generated by the command</returns>
1465         public static XmlReader ExecuteXmlReader(SqlTransaction transaction, CommandType commandType, string commandText, params SqlParameter[] commandParameters)
1466         {
1467             if( transaction == null ) throw new ArgumentNullException( "transaction" );
1468             if( transaction != null && transaction.Connection == null ) throw new ArgumentException( "The transaction was rollbacked or commited, please provide an open transaction.", "transaction" );
1469 
1470             // Create a command and prepare it for execution
1471             SqlCommand cmd = new SqlCommand();
1472             bool mustCloseConnection = false;
1473             PrepareCommand(cmd, transaction.Connection, transaction, commandType, commandText, commandParameters, out mustCloseConnection );
1474             
1475             // Create the DataAdapter & DataSet
1476             XmlReader retval = cmd.ExecuteXmlReader();
1477             
1478             // Detach the SqlParameters from the command object, so they can be used again
1479             cmd.Parameters.Clear();
1480             return retval;            
1481         }
1482 
1483         /// <summary>
1484         /// Execute a stored procedure via a SqlCommand (that returns a resultset) against the specified 
1485         /// SqlTransaction using the provided parameter values.  This method will query the database to discover the parameters for the 
1486         /// stored procedure (the first time each stored procedure is called), and assign the values based on parameter order.
1487         /// </summary>
1488         /// <remarks>
1489         /// This method provides no access to output parameters or the stored procedure's return value parameter.
1490         /// 
1491         /// e.g.:  
1492         ///  XmlReader r = ExecuteXmlReader(trans, "GetOrders", 24, 36);
1493         /// </remarks>
1494         /// <param name="transaction">A valid SqlTransaction</param>
1495         /// <param name="spName">The name of the stored procedure</param>
1496         /// <param name="parameterValues">An array of objects to be assigned as the input values of the stored procedure</param>
1497         /// <returns>A dataset containing the resultset generated by the command</returns>
1498         public static XmlReader ExecuteXmlReader(SqlTransaction transaction, string spName, params object[] parameterValues)
1499         {
1500             if( transaction == null ) throw new ArgumentNullException( "transaction" );
1501             if( transaction != null && transaction.Connection == null ) throw new ArgumentException( "The transaction was rollbacked or commited, please provide an open transaction.", "transaction" );
1502             if( spName == null || spName.Length == 0 ) throw new ArgumentNullException( "spName" );
1503 
1504             // If we receive parameter values, we need to figure out where they go
1505             if ((parameterValues != null) && (parameterValues.Length > 0)) 
1506             {
1507                 // Pull the parameters for this stored procedure from the parameter cache (or discover them & populate the cache)
1508                 SqlParameter[] commandParameters = SqlHelperParameterCache.GetSpParameterSet(transaction.Connection, spName);
1509 
1510                 // Assign the provided values to these parameters based on parameter order
1511                 AssignParameterValues(commandParameters, parameterValues);
1512 
1513                 // Call the overload that takes an array of SqlParameters
1514                 return ExecuteXmlReader(transaction, CommandType.StoredProcedure, spName, commandParameters);
1515             }
1516             else 
1517             {
1518                 // Otherwise we can just call the SP without params
1519                 return ExecuteXmlReader(transaction, CommandType.StoredProcedure, spName);
1520             }
1521         }
1522 
1523         #endregion ExecuteXmlReader
1524 
1525         #region FillDataset
1526         /// <summary>
1527         /// Execute a SqlCommand (that returns a resultset and takes no parameters) against the database specified in 
1528         /// the connection string. 
1529         /// </summary>
1530         /// <remarks>
1531         /// e.g.:  
1532         ///  FillDataset(connString, CommandType.StoredProcedure, "GetOrders", ds, new string[] {"orders"});
1533         /// </remarks>
1534         /// <param name="connectionString">A valid connection string for a SqlConnection</param>
1535         /// <param name="commandType">The CommandType (stored procedure, text, etc.)</param>
1536         /// <param name="commandText">The stored procedure name or T-SQL command</param>
1537         /// <param name="dataSet">A dataset wich will contain the resultset generated by the command</param>
1538         /// <param name="tableNames">This array will be used to create table mappings allowing the DataTables to be referenced
1539         /// by a user defined name (probably the actual table name)</param>
1540         public static void FillDataset(string connectionString, CommandType commandType, string commandText, DataSet dataSet, string[] tableNames)
1541         {
1542             if( connectionString == null || connectionString.Length == 0 ) throw new ArgumentNullException( "connectionString" );
1543             if( dataSet == null ) throw new ArgumentNullException( "dataSet" );
1544             
1545             // Create & open a SqlConnection, and dispose of it after we are done
1546             using (SqlConnection connection = new SqlConnection(connectionString))
1547             {
1548                 connection.Open();
1549 
1550                 // Call the overload that takes a connection in place of the connection string
1551                 FillDataset(connection, commandType, commandText, dataSet, tableNames);
1552             }
1553         }
1554 
1555         /// <summary>
1556         /// Execute a SqlCommand (that returns a resultset) against the database specified in the connection string 
1557         /// using the provided parameters.
1558         /// </summary>
1559         /// <remarks>
1560         /// e.g.:  
1561         ///  FillDataset(connString, CommandType.StoredProcedure, "GetOrders", ds, new string[] {"orders"}, new SqlParameter("@prodid", 24));
1562         /// </remarks>
1563         /// <param name="connectionString">A valid connection string for a SqlConnection</param>
1564         /// <param name="commandType">The CommandType (stored procedure, text, etc.)</param>
1565         /// <param name="commandText">The stored procedure name or T-SQL command</param>
1566         /// <param name="commandParameters">An array of SqlParamters used to execute the command</param>
1567         /// <param name="dataSet">A dataset wich will contain the resultset generated by the command</param>
1568         /// <param name="tableNames">This array will be used to create table mappings allowing the DataTables to be referenced
1569         /// by a user defined name (probably the actual table name)
1570         /// </param>
1571         public static void FillDataset(string connectionString, CommandType commandType,
1572             string commandText, DataSet dataSet, string[] tableNames,
1573             params SqlParameter[] commandParameters)
1574         {
1575             if( connectionString == null || connectionString.Length == 0 ) throw new ArgumentNullException( "connectionString" );
1576             if( dataSet == null ) throw new ArgumentNullException( "dataSet" );
1577             // Create & open a SqlConnection, and dispose of it after we are done
1578             using (SqlConnection connection = new SqlConnection(connectionString))
1579             {
1580                 connection.Open();
1581 
1582                 // Call the overload that takes a connection in place of the connection string
1583                 FillDataset(connection, commandType, commandText, dataSet, tableNames, commandParameters);
1584             }
1585         }
1586 
1587         /// <summary>
1588         /// Execute a stored procedure via a SqlCommand (that returns a resultset) against the database specified in 
1589         /// the connection string using the provided parameter values.  This method will query the database to discover the parameters for the 
1590         /// stored procedure (the first time each stored procedure is called), and assign the values based on parameter order.
1591         /// </summary>
1592         /// <remarks>
1593         /// This method provides no access to output parameters or the stored procedure's return value parameter.
1594         /// 
1595         /// e.g.:  
1596         ///  FillDataset(connString, CommandType.StoredProcedure, "GetOrders", ds, new string[] {"orders"}, 24);
1597         /// </remarks>
1598         /// <param name="connectionString">A valid connection string for a SqlConnection</param>
1599         /// <param name="spName">The name of the stored procedure</param>
1600         /// <param name="dataSet">A dataset wich will contain the resultset generated by the command</param>
1601         /// <param name="tableNames">This array will be used to create table mappings allowing the DataTables to be referenced
1602         /// by a user defined name (probably the actual table name)
1603         /// </param>    
1604         /// <param name="parameterValues">An array of objects to be assigned as the input values of the stored procedure</param>
1605         public static void FillDataset(string connectionString, string spName,
1606             DataSet dataSet, string[] tableNames,
1607             params object[] parameterValues)
1608         {
1609             if( connectionString == null || connectionString.Length == 0 ) throw new ArgumentNullException( "connectionString" );
1610             if( dataSet == null ) throw new ArgumentNullException( "dataSet" );
1611             // Create & open a SqlConnection, and dispose of it after we are done
1612             using (SqlConnection connection = new SqlConnection(connectionString))
1613             {
1614                 connection.Open();
1615 
1616                 // Call the overload that takes a connection in place of the connection string
1617                 FillDataset (connection, spName, dataSet, tableNames, parameterValues);
1618             }
1619         }
1620 
1621         /// <summary>
1622         /// Execute a SqlCommand (that returns a resultset and takes no parameters) against the provided SqlConnection. 
1623         /// </summary>
1624         /// <remarks>
1625         /// e.g.:  
1626         ///  FillDataset(conn, CommandType.StoredProcedure, "GetOrders", ds, new string[] {"orders"});
1627         /// </remarks>
1628         /// <param name="connection">A valid SqlConnection</param>
1629         /// <param name="commandType">The CommandType (stored procedure, text, etc.)</param>
1630         /// <param name="commandText">The stored procedure name or T-SQL command</param>
1631         /// <param name="dataSet">A dataset wich will contain the resultset generated by the command</param>
1632         /// <param name="tableNames">This array will be used to create table mappings allowing the DataTables to be referenced
1633         /// by a user defined name (probably the actual table name)
1634         /// </param>    
1635         public static void FillDataset(SqlConnection connection, CommandType commandType, 
1636             string commandText, DataSet dataSet, string[] tableNames)
1637         {
1638             FillDataset(connection, commandType, commandText, dataSet, tableNames, null);
1639         }
1640 
1641         /// <summary>
1642         /// Execute a SqlCommand (that returns a resultset) against the specified SqlConnection 
1643         /// using the provided parameters.
1644         /// </summary>
1645         /// <remarks>
1646         /// e.g.:  
1647         ///  FillDataset(conn, CommandType.StoredProcedure, "GetOrders", ds, new string[] {"orders"}, new SqlParameter("@prodid", 24));
1648         /// </remarks>
1649         /// <param name="connection">A valid SqlConnection</param>
1650         /// <param name="commandType">The CommandType (stored procedure, text, etc.)</param>
1651         /// <param name="commandText">The stored procedure name or T-SQL command</param>
1652         /// <param name="dataSet">A dataset wich will contain the resultset generated by the command</param>
1653         /// <param name="tableNames">This array will be used to create table mappings allowing the DataTables to be referenced
1654         /// by a user defined name (probably the actual table name)
1655         /// </param>
1656         /// <param name="commandParameters">An array of SqlParamters used to execute the command</param>
1657         public static void FillDataset(SqlConnection connection, CommandType commandType, 
1658             string commandText, DataSet dataSet, string[] tableNames,
1659             params SqlParameter[] commandParameters)
1660         {
1661             FillDataset(connection, null, commandType, commandText, dataSet, tableNames, commandParameters);
1662         }
1663 
1664         /// <summary>
1665         /// Execute a stored procedure via a SqlCommand (that returns a resultset) against the specified SqlConnection 
1666         /// using the provided parameter values.  This method will query the database to discover the parameters for the 
1667         /// stored procedure (the first time each stored procedure is called), and assign the values based on parameter order.
1668         /// </summary>
1669         /// <remarks>
1670         /// This method provides no access to output parameters or the stored procedure's return value parameter.
1671         /// 
1672         /// e.g.:  
1673         ///  FillDataset(conn, "GetOrders", ds, new string[] {"orders"}, 24, 36);
1674         /// </remarks>
1675         /// <param name="connection">A valid SqlConnection</param>
1676         /// <param name="spName">The name of the stored procedure</param>
1677         /// <param name="dataSet">A dataset wich will contain the resultset generated by the command</param>
1678         /// <param name="tableNames">This array will be used to create table mappings allowing the DataTables to be referenced
1679         /// by a user defined name (probably the actual table name)
1680         /// </param>
1681         /// <param name="parameterValues">An array of objects to be assigned as the input values of the stored procedure</param>
1682         public static void FillDataset(SqlConnection connection, string spName, 
1683             DataSet dataSet, string[] tableNames,
1684             params object[] parameterValues)
1685         {
1686             if ( connection == null ) throw new ArgumentNullException( "connection" );
1687             if (dataSet == null ) throw new ArgumentNullException( "dataSet" );
1688             if( spName == null || spName.Length == 0 ) throw new ArgumentNullException( "spName" );
1689 
1690             // If we receive parameter values, we need to figure out where they go
1691             if ((parameterValues != null) && (parameterValues.Length > 0)) 
1692             {
1693                 // Pull the parameters for this stored procedure from the parameter cache (or discover them & populate the cache)
1694                 SqlParameter[] commandParameters = SqlHelperParameterCache.GetSpParameterSet(connection, spName);
1695 
1696                 // Assign the provided values to these parameters based on parameter order
1697                 AssignParameterValues(commandParameters, parameterValues);
1698 
1699                 // Call the overload that takes an array of SqlParameters
1700                 FillDataset(connection, CommandType.StoredProcedure, spName, dataSet, tableNames, commandParameters);
1701             }
1702             else 
1703             {
1704                 // Otherwise we can just call the SP without params
1705                 FillDataset(connection, CommandType.StoredProcedure, spName, dataSet, tableNames);
1706             }    
1707         }
1708 
1709         /// <summary>
1710         /// Execute a SqlCommand (that returns a resultset and takes no parameters) against the provided SqlTransaction. 
1711         /// </summary>
1712         /// <remarks>
1713         /// e.g.:  
1714         ///  FillDataset(trans, CommandType.StoredProcedure, "GetOrders", ds, new string[] {"orders"});
1715         /// </remarks>
1716         /// <param name="transaction">A valid SqlTransaction</param>
1717         /// <param name="commandType">The CommandType (stored procedure, text, etc.)</param>
1718         /// <param name="commandText">The stored procedure name or T-SQL command</param>
1719         /// <param name="dataSet">A dataset wich will contain the resultset generated by the command</param>
1720         /// <param name="tableNames">This array will be used to create table mappings allowing the DataTables to be referenced
1721         /// by a user defined name (probably the actual table name)
1722         /// </param>
1723         public static void FillDataset(SqlTransaction transaction, CommandType commandType, 
1724             string commandText,
1725             DataSet dataSet, string[] tableNames)
1726         {
1727             FillDataset (transaction, commandType, commandText, dataSet, tableNames, null);    
1728         }
1729 
1730         /// <summary>
1731         /// Execute a SqlCommand (that returns a resultset) against the specified SqlTransaction
1732         /// using the provided parameters.
1733         /// </summary>
1734         /// <remarks>
1735         /// e.g.:  
1736         ///  FillDataset(trans, CommandType.StoredProcedure, "GetOrders", ds, new string[] {"orders"}, new SqlParameter("@prodid", 24));
1737         /// </remarks>
1738         /// <param name="transaction">A valid SqlTransaction</param>
1739         /// <param name="commandType">The CommandType (stored procedure, text, etc.)</param>
1740         /// <param name="commandText">The stored procedure name or T-SQL command</param>
1741         /// <param name="dataSet">A dataset wich will contain the resultset generated by the command</param>
1742         /// <param name="tableNames">This array will be used to create table mappings allowing the DataTables to be referenced
1743         /// by a user defined name (probably the actual table name)
1744         /// </param>
1745         /// <param name="commandParameters">An array of SqlParamters used to execute the command</param>
1746         public static void FillDataset(SqlTransaction transaction, CommandType commandType, 
1747             string commandText, DataSet dataSet, string[] tableNames,
1748             params SqlParameter[] commandParameters)
1749         {
1750             FillDataset(transaction.Connection, transaction, commandType, commandText, dataSet, tableNames, commandParameters);
1751         }
1752 
1753         /// <summary>
1754         /// Execute a stored procedure via a SqlCommand (that returns a resultset) against the specified 
1755         /// SqlTransaction using the provided parameter values.  This method will query the database to discover the parameters for the 
1756         /// stored procedure (the first time each stored procedure is called), and assign the values based on parameter order.
1757         /// </summary>
1758         /// <remarks>
1759         /// This method provides no access to output parameters or the stored procedure's return value parameter.
1760         /// 
1761         /// e.g.:  
1762         ///  FillDataset(trans, "GetOrders", ds, new string[]{"orders"}, 24, 36);
1763         /// </remarks>
1764         /// <param name="transaction">A valid SqlTransaction</param>
1765         /// <param name="spName">The name of the stored procedure</param>
1766         /// <param name="dataSet">A dataset wich will contain the resultset generated by the command</param>
1767         /// <param name="tableNames">This array will be used to create table mappings allowing the DataTables to be referenced
1768         /// by a user defined name (probably the actual table name)
1769         /// </param>
1770         /// <param name="parameterValues">An array of objects to be assigned as the input values of the stored procedure</param>
1771         public static void FillDataset(SqlTransaction transaction, string spName,
1772             DataSet dataSet, string[] tableNames,
1773             params object[] parameterValues) 
1774         {
1775             if( transaction == null ) throw new ArgumentNullException( "transaction" );
1776             if( transaction != null && transaction.Connection == null ) throw new ArgumentException( "The transaction was rollbacked or commited, please provide an open transaction.", "transaction" );
1777             if( dataSet == null ) throw new ArgumentNullException( "dataSet" );
1778             if( spName == null || spName.Length == 0 ) throw new ArgumentNullException( "spName" );
1779 
1780             // If we receive parameter values, we need to figure out where they go
1781             if ((parameterValues != null) && (parameterValues.Length > 0)) 
1782             {
1783                 // Pull the parameters for this stored procedure from the parameter cache (or discover them & populate the cache)
1784                 SqlParameter[] commandParameters = SqlHelperParameterCache.GetSpParameterSet(transaction.Connection, spName);
1785 
1786                 // Assign the provided values to these parameters based on parameter order
1787                 AssignParameterValues(commandParameters, parameterValues);
1788 
1789                 // Call the overload that takes an array of SqlParameters
1790                 FillDataset(transaction, CommandType.StoredProcedure, spName, dataSet, tableNames, commandParameters);
1791             }
1792             else 
1793             {
1794                 // Otherwise we can just call the SP without params
1795                 FillDataset(transaction, CommandType.StoredProcedure, spName, dataSet, tableNames);
1796             }    
1797         }
1798 
1799         /// <summary>
1800         /// Private helper method that execute a SqlCommand (that returns a resultset) against the specified SqlTransaction and SqlConnection
1801         /// using the provided parameters.
1802         /// </summary>
1803         /// <remarks>
1804         /// e.g.:  
1805         ///  FillDataset(conn, trans, CommandType.StoredProcedure, "GetOrders", ds, new string[] {"orders"}, new SqlParameter("@prodid", 24));
1806         /// </remarks>
1807         /// <param name="connection">A valid SqlConnection</param>
1808         /// <param name="transaction">A valid SqlTransaction</param>
1809         /// <param name="commandType">The CommandType (stored procedure, text, etc.)</param>
1810         /// <param name="commandText">The stored procedure name or T-SQL command</param>
1811         /// <param name="dataSet">A dataset wich will contain the resultset generated by the command</param>
1812         /// <param name="tableNames">This array will be used to create table mappings allowing the DataTables to be referenced
1813         /// by a user defined name (probably the actual table name)
1814         /// </param>
1815         /// <param name="commandParameters">An array of SqlParamters used to execute the command</param>
1816         private static void FillDataset(SqlConnection connection, SqlTransaction transaction, CommandType commandType, 
1817             string commandText, DataSet dataSet, string[] tableNames,
1818             params SqlParameter[] commandParameters)
1819         {
1820             if( connection == null ) throw new ArgumentNullException( "connection" );
1821             if( dataSet == null ) throw new ArgumentNullException( "dataSet" );
1822 
1823             // Create a command and prepare it for execution
1824             SqlCommand command = new SqlCommand();
1825             bool mustCloseConnection = false;
1826             PrepareCommand(command, connection, transaction, commandType, commandText, commandParameters, out mustCloseConnection );
1827                 
1828             // Create the DataAdapter & DataSet
1829             using( SqlDataAdapter dataAdapter = new SqlDataAdapter(command) )
1830             {
1831                 
1832                 // Add the table mappings specified by the user
1833                 if (tableNames != null && tableNames.Length > 0)
1834                 {
1835                     string tableName = "Table";
1836                     for (int index=0; index < tableNames.Length; index++)
1837                     {
1838                         if( tableNames[index] == null || tableNames[index].Length == 0 ) throw new ArgumentException( "The tableNames parameter must contain a list of tables, a value was provided as null or empty string.", "tableNames" );
1839                         dataAdapter.TableMappings.Add(tableName, tableNames[index]);
1840                         tableName += (index + 1).ToString();
1841                     }
1842                 }
1843                 
1844                 // Fill the DataSet using default values for DataTable names, etc
1845                 dataAdapter.Fill(dataSet);
1846 
1847                 // Detach the SqlParameters from the command object, so they can be used again
1848                 command.Parameters.Clear();
1849             }
1850 
1851             if( mustCloseConnection )
1852                 connection.Close();
1853         }
1854         #endregion
1855         
1856         #region UpdateDataset
1857         /// <summary>
1858         /// Executes the respective command for each inserted, updated, or deleted row in the DataSet.
1859         /// </summary>
1860         /// <remarks>
1861         /// e.g.:  
1862         ///  UpdateDataset(conn, insertCommand, deleteCommand, updateCommand, dataSet, "Order");
1863         /// </remarks>
1864         /// <param name="insertCommand">A valid transact-SQL statement or stored procedure to insert new records into the data source</param>
1865         /// <param name="deleteCommand">A valid transact-SQL statement or stored procedure to delete records from the data source</param>
1866         /// <param name="updateCommand">A valid transact-SQL statement or stored procedure used to update records in the data source</param>
1867         /// <param name="dataSet">The DataSet used to update the data source</param>
1868         /// <param name="tableName">The DataTable used to update the data source.</param>
1869         public static void UpdateDataset(SqlCommand insertCommand, SqlCommand deleteCommand, SqlCommand updateCommand, DataSet dataSet, string tableName)
1870         {
1871             if( insertCommand == null ) throw new ArgumentNullException( "insertCommand" );
1872             if( deleteCommand == null ) throw new ArgumentNullException( "deleteCommand" );
1873             if( updateCommand == null ) throw new ArgumentNullException( "updateCommand" );
1874             if( tableName == null || tableName.Length == 0 ) throw new ArgumentNullException( "tableName" ); 
1875 
1876             // Create a SqlDataAdapter, and dispose of it after we are done
1877             using (SqlDataAdapter dataAdapter = new SqlDataAdapter())
1878             {
1879                 // Set the data adapter commands
1880                 dataAdapter.UpdateCommand = updateCommand;
1881                 dataAdapter.InsertCommand = insertCommand;
1882                 dataAdapter.DeleteCommand = deleteCommand;
1883 
1884                 // Update the dataset changes in the data source
1885                 dataAdapter.Update (dataSet, tableName); 
1886 
1887                 // Commit all the changes made to the DataSet
1888                 dataSet.AcceptChanges();
1889             }
1890         }
1891         #endregion
1892 
1893         #region CreateCommand
1894         /// <summary>
1895         /// Simplify the creation of a Sql command object by allowing
1896         /// a stored procedure and optional parameters to be provided
1897         /// </summary>
1898         /// <remarks>
1899         /// e.g.:  
1900         ///  SqlCommand command = CreateCommand(conn, "AddCustomer", "CustomerID", "CustomerName");
1901         /// </remarks>
1902         /// <param name="connection">A valid SqlConnection object</param>
1903         /// <param name="spName">The name of the stored procedure</param>
1904         /// <param name="sourceColumns">An array of string to be assigned as the source columns of the stored procedure parameters</param>
1905         /// <returns>A valid SqlCommand object</returns>
1906         public static SqlCommand CreateCommand(SqlConnection connection, string spName, params string[] sourceColumns) 
1907         {
1908             if( connection == null ) throw new ArgumentNullException( "connection" );
1909             if( spName == null || spName.Length == 0 ) throw new ArgumentNullException( "spName" );
1910 
1911             // Create a SqlCommand
1912             SqlCommand cmd = new SqlCommand( spName, connection );
1913             cmd.CommandType = CommandType.StoredProcedure;
1914 
1915             // If we receive parameter values, we need to figure out where they go
1916             if ((sourceColumns != null) && (sourceColumns.Length > 0)) 
1917             {
1918                 // Pull the parameters for this stored procedure from the parameter cache (or discover them & populate the cache)
1919                 SqlParameter[] commandParameters = SqlHelperParameterCache.GetSpParameterSet(connection, spName);
1920 
1921                 // Assign the provided source columns to these parameters based on parameter order
1922                 for (int index=0; index < sourceColumns.Length; index++)
1923                     commandParameters[index].SourceColumn = sourceColumns[index];
1924 
1925                 // Attach the discovered parameters to the SqlCommand object
1926                 AttachParameters (cmd, commandParameters);
1927             }
1928 
1929             return cmd;
1930         }
1931         #endregion
1932 
1933         #region ExecuteNonQueryTypedParams
1934         /// <summary>
1935         /// Execute a stored procedure via a SqlCommand (that returns no resultset) against the database specified in 
1936         /// the connection string using the dataRow column values as the stored procedure's parameters values.
1937         /// This method will query the database to discover the parameters for the 
1938         /// stored procedure (the first time each stored procedure is called), and assign the values based on row values.
1939         /// </summary>
1940         /// <param name="connectionString">A valid connection string for a SqlConnection</param>
1941         /// <param name="spName">The name of the stored procedure</param>
1942         /// <param name="dataRow">The dataRow used to hold the stored procedure's parameter values.</param>
1943         /// <returns>An int representing the number of rows affected by the command</returns>
1944         public static int ExecuteNonQueryTypedParams(String connectionString, String spName, DataRow dataRow)
1945         {
1946             if( connectionString == null || connectionString.Length == 0 ) throw new ArgumentNullException( "connectionString" );
1947             if( spName == null || spName.Length == 0 ) throw new ArgumentNullException( "spName" );
1948             
1949             // If the row has values, the store procedure parameters must be initialized
1950             if (dataRow != null && dataRow.ItemArray.Length > 0)
1951             {
1952                 // Pull the parameters for this stored procedure from the parameter cache (or discover them & populate the cache)
1953                 SqlParameter[] commandParameters = SqlHelperParameterCache.GetSpParameterSet(connectionString, spName);
1954                 
1955                 // Set the parameters values
1956                 AssignParameterValues(commandParameters, dataRow);
1957                                 
1958                 return SqlHelper.ExecuteNonQuery(connectionString, CommandType.StoredProcedure, spName, commandParameters);
1959             }
1960             else
1961             {
1962                 return SqlHelper.ExecuteNonQuery(connectionString, CommandType.StoredProcedure, spName);
1963             }
1964         }
1965 
1966         /// <summary>
1967         /// Execute a stored procedure via a SqlCommand (that returns no resultset) against the specified SqlConnection 
1968         /// using the dataRow column values as the stored procedure's parameters values.  
1969         /// This method will query the database to discover the parameters for the 
1970         /// stored procedure (the first time each stored procedure is called), and assign the values based on row values.
1971         /// </summary>
1972         /// <param name="connection">A valid SqlConnection object</param>
1973         /// <param name="spName">The name of the stored procedure</param>
1974         /// <param name="dataRow">The dataRow used to hold the stored procedure's parameter values.</param>
1975         /// <returns>An int representing the number of rows affected by the command</returns>
1976         public static int ExecuteNonQueryTypedParams(SqlConnection connection, String spName, DataRow dataRow)
1977         {
1978             if( connection == null ) throw new ArgumentNullException( "connection" );
1979             if( spName == null || spName.Length == 0 ) throw new ArgumentNullException( "spName" );
1980 
1981             // If the row has values, the store procedure parameters must be initialized
1982             if (dataRow != null && dataRow.ItemArray.Length > 0)
1983             {
1984                 // Pull the parameters for this stored procedure from the parameter cache (or discover them & populate the cache)
1985                 SqlParameter[] commandParameters = SqlHelperParameterCache.GetSpParameterSet(connection, spName);
1986                 
1987                 // Set the parameters values
1988                 AssignParameterValues(commandParameters, dataRow);
1989                                 
1990                 return SqlHelper.ExecuteNonQuery(connection, CommandType.StoredProcedure, spName, commandParameters);
1991             }
1992             else
1993             {
1994                 return SqlHelper.ExecuteNonQuery(connection, CommandType.StoredProcedure, spName);
1995             }
1996         }
1997 
1998         /// <summary>
1999         /// Execute a stored procedure via a SqlCommand (that returns no resultset) against the specified
2000         /// SqlTransaction using the dataRow column values as the stored procedure's parameters values.
2001         /// This method will query the database to discover the parameters for the 
2002         /// stored procedure (the first time each stored procedure is called), and assign the values based on row values.
2003         /// </summary>
2004         /// <param name="transaction">A valid SqlTransaction object</param>
2005         /// <param name="spName">The name of the stored procedure</param>
2006         /// <param name="dataRow">The dataRow used to hold the stored procedure's parameter values.</param>
2007         /// <returns>An int representing the number of rows affected by the command</returns>
2008         public static int ExecuteNonQueryTypedParams(SqlTransaction transaction, String spName, DataRow dataRow)
2009         {
2010             if( transaction == null ) throw new ArgumentNullException( "transaction" );
2011             if( transaction != null && transaction.Connection == null ) throw new ArgumentException( "The transaction was rollbacked or commited, please provide an open transaction.", "transaction" );
2012             if( spName == null || spName.Length == 0 ) throw new ArgumentNullException( "spName" );
2013 
2014             // Sf the row has values, the store procedure parameters must be initialized
2015             if (dataRow != null && dataRow.ItemArray.Length > 0)
2016             {
2017                 // Pull the parameters for this stored procedure from the parameter cache (or discover them & populate the cache)
2018                 SqlParameter[] commandParameters = SqlHelperParameterCache.GetSpParameterSet(transaction.Connection, spName);
2019                 
2020                 // Set the parameters values
2021                 AssignParameterValues(commandParameters, dataRow);
2022                                 
2023                 return SqlHelper.ExecuteNonQuery(transaction, CommandType.StoredProcedure, spName, commandParameters);
2024             }
2025             else
2026             {
2027                 return SqlHelper.ExecuteNonQuery(transaction, CommandType.StoredProcedure, spName);
2028             }
2029         }
2030         #endregion
2031 
2032         #region ExecuteDatasetTypedParams
2033         /// <summary>
2034         /// Execute a stored procedure via a SqlCommand (that returns a resultset) against the database specified in 
2035         /// the connection string using the dataRow column values as the stored procedure's parameters values.
2036         /// This method will query the database to discover the parameters for the 
2037         /// stored procedure (the first time each stored procedure is called), and assign the values based on row values.
2038         /// </summary>
2039         /// <param name="connectionString">A valid connection string for a SqlConnection</param>
2040         /// <param name="spName">The name of the stored procedure</param>
2041         /// <param name="dataRow">The dataRow used to hold the stored procedure's parameter values.</param>
2042         /// <returns>A dataset containing the resultset generated by the command</returns>
2043         public static DataSet ExecuteDatasetTypedParams(string connectionString, String spName, DataRow dataRow)
2044         {
2045             if( connectionString == null || connectionString.Length == 0 ) throw new ArgumentNullException( "connectionString" );
2046             if( spName == null || spName.Length == 0 ) throw new ArgumentNullException( "spName" );
2047 
2048             //If the row has values, the store procedure parameters must be initialized
2049             if ( dataRow != null && dataRow.ItemArray.Length > 0)
2050             {
2051                 // Pull the parameters for this stored procedure from the parameter cache (or discover them & populate the cache)
2052                 SqlParameter[] commandParameters = SqlHelperParameterCache.GetSpParameterSet(connectionString, spName);
2053                 
2054                 // Set the parameters values
2055                 AssignParameterValues(commandParameters, dataRow);
2056                 
2057                 return SqlHelper.ExecuteDataset(connectionString, CommandType.StoredProcedure, spName, commandParameters);
2058             }
2059             else
2060             {
2061                 return SqlHelper.ExecuteDataset(connectionString, CommandType.StoredProcedure, spName);
2062             }
2063         }
2064 
2065         /// <summary>
2066         /// Execute a stored procedure via a SqlCommand (that returns a resultset) against the specified SqlConnection 
2067         /// using the dataRow column values as the store procedure's parameters values.
2068         /// This method will query the database to discover the parameters for the 
2069         /// stored procedure (the first time each stored procedure is called), and assign the values based on row values.
2070         /// </summary>
2071         /// <param name="connection">A valid SqlConnection object</param>
2072         /// <param name="spName">The name of the stored procedure</param>
2073         /// <param name="dataRow">The dataRow used to hold the stored procedure's parameter values.</param>
2074         /// <returns>A dataset containing the resultset generated by the command</returns>
2075         public static DataSet ExecuteDatasetTypedParams(SqlConnection connection, String spName, DataRow dataRow)
2076         {
2077             if( connection == null ) throw new ArgumentNullException( "connection" );
2078             if( spName == null || spName.Length == 0 ) throw new ArgumentNullException( "spName" );
2079 
2080             // If the row has values, the store procedure parameters must be initialized
2081             if( dataRow != null && dataRow.ItemArray.Length > 0)
2082             {
2083                 // Pull the parameters for this stored procedure from the parameter cache (or discover them & populate the cache)
2084                 SqlParameter[] commandParameters = SqlHelperParameterCache.GetSpParameterSet(connection, spName);
2085                 
2086                 // Set the parameters values
2087                 AssignParameterValues(commandParameters, dataRow);
2088                 
2089                 return SqlHelper.ExecuteDataset(connection, CommandType.StoredProcedure, spName, commandParameters);
2090             }
2091             else
2092             {
2093                 return SqlHelper.ExecuteDataset(connection, CommandType.StoredProcedure, spName);
2094             }
2095         }
2096 
2097         /// <summary>
2098         /// Execute a stored procedure via a SqlCommand (that returns a resultset) against the specified SqlTransaction 
2099         /// using the dataRow column values as the stored procedure's parameters values.
2100         /// This method will query the database to discover the parameters for the 
2101         /// stored procedure (the first time each stored procedure is called), and assign the values based on row values.
2102         /// </summary>
2103         /// <param name="transaction">A valid SqlTransaction object</param>
2104         /// <param name="spName">The name of the stored procedure</param>
2105         /// <param name="dataRow">The dataRow used to hold the stored procedure's parameter values.</param>
2106         /// <returns>A dataset containing the resultset generated by the command</returns>
2107         public static DataSet ExecuteDatasetTypedParams(SqlTransaction transaction, String spName, DataRow dataRow)
2108         {
2109             if( transaction == null ) throw new ArgumentNullException( "transaction" );
2110             if( transaction != null && transaction.Connection == null ) throw new ArgumentException( "The transaction was rollbacked or commited, please provide an open transaction.", "transaction" );
2111             if( spName == null || spName.Length == 0 ) throw new ArgumentNullException( "spName" );
2112 
2113             // If the row has values, the store procedure parameters must be initialized
2114             if( dataRow != null && dataRow.ItemArray.Length > 0)
2115             {
2116                 // Pull the parameters for this stored procedure from the parameter cache (or discover them & populate the cache)
2117                 SqlParameter[] commandParameters = SqlHelperParameterCache.GetSpParameterSet(transaction.Connection, spName);
2118                 
2119                 // Set the parameters values
2120                 AssignParameterValues(commandParameters, dataRow);
2121                 
2122                 return SqlHelper.ExecuteDataset(transaction, CommandType.StoredProcedure, spName, commandParameters);
2123             }
2124             else
2125             {
2126                 return SqlHelper.ExecuteDataset(transaction, CommandType.StoredProcedure, spName);
2127             }
2128         }
2129 
2130         #endregion
2131 
2132         #region ExecuteReaderTypedParams
2133         /// <summary>
2134         /// Execute a stored procedure via a SqlCommand (that returns a resultset) against the database specified in 
2135         /// the connection string using the dataRow column values as the stored procedure's parameters values.
2136         /// This method will query the database to discover the parameters for the 
2137         /// stored procedure (the first time each stored procedure is called), and assign the values based on parameter order.
2138         /// </summary>
2139         /// <param name="connectionString">A valid connection string for a SqlConnection</param>
2140         /// <param name="spName">The name of the stored procedure</param>
2141         /// <param name="dataRow">The dataRow used to hold the stored procedure's parameter values.</param>
2142         /// <returns>A SqlDataReader containing the resultset generated by the command</returns>
2143         public static SqlDataReader ExecuteReaderTypedParams(String connectionString, String spName, DataRow dataRow)
2144         {
2145             if( connectionString == null || connectionString.Length == 0 ) throw new ArgumentNullException( "connectionString" );
2146             if( spName == null || spName.Length == 0 ) throw new ArgumentNullException( "spName" );
2147             
2148             // If the row has values, the store procedure parameters must be initialized
2149             if ( dataRow != null && dataRow.ItemArray.Length > 0 )
2150             {
2151                 // Pull the parameters for this stored procedure from the parameter cache (or discover them & populate the cache)
2152                 SqlParameter[] commandParameters = SqlHelperParameterCache.GetSpParameterSet(connectionString, spName);
2153                 
2154                 // Set the parameters values
2155                 AssignParameterValues(commandParameters, dataRow);
2156                 
2157                 return SqlHelper.ExecuteReader(connectionString, CommandType.StoredProcedure, spName, commandParameters);
2158             }
2159             else
2160             {
2161                 return SqlHelper.ExecuteReader(connectionString, CommandType.StoredProcedure, spName);
2162             }
2163         }
2164 
2165                 
2166         /// <summary>
2167         /// Execute a stored procedure via a SqlCommand (that returns a resultset) against the specified SqlConnection 
2168         /// using the dataRow column values as the stored procedure's parameters values.
2169         /// This method will query the database to discover the parameters for the 
2170         /// stored procedure (the first time each stored procedure is called), and assign the values based on parameter order.
2171         /// </summary>
2172         /// <param name="connection">A valid SqlConnection object</param>
2173         /// <param name="spName">The name of the stored procedure</param>
2174         /// <param name="dataRow">The dataRow used to hold the stored procedure's parameter values.</param>
2175         /// <returns>A SqlDataReader containing the resultset generated by the command</returns>
2176         public static SqlDataReader ExecuteReaderTypedParams(SqlConnection connection, String spName, DataRow dataRow)
2177         {
2178             if( connection == null ) throw new ArgumentNullException( "connection" );
2179             if( spName == null || spName.Length == 0 ) throw new ArgumentNullException( "spName" );
2180 
2181             // If the row has values, the store procedure parameters must be initialized
2182             if( dataRow != null && dataRow.ItemArray.Length > 0)
2183             {
2184                 // Pull the parameters for this stored procedure from the parameter cache (or discover them & populate the cache)
2185                 SqlParameter[] commandParameters = SqlHelperParameterCache.GetSpParameterSet(connection, spName);
2186                 
2187                 // Set the parameters values
2188                 AssignParameterValues(commandParameters, dataRow);
2189                 
2190                 return SqlHelper.ExecuteReader(connection, CommandType.StoredProcedure, spName, commandParameters);
2191             }
2192             else
2193             {
2194                 return SqlHelper.ExecuteReader(connection, CommandType.StoredProcedure, spName);
2195             }
2196         }
2197         
2198         /// <summary>
2199         /// Execute a stored procedure via a SqlCommand (that returns a resultset) against the specified SqlTransaction 
2200         /// using the dataRow column values as the stored procedure's parameters values.
2201         /// This method will query the database to discover the parameters for the 
2202         /// stored procedure (the first time each stored procedure is called), and assign the values based on parameter order.
2203         /// </summary>
2204         /// <param name="transaction">A valid SqlTransaction object</param>
2205         /// <param name="spName">The name of the stored procedure</param>
2206         /// <param name="dataRow">The dataRow used to hold the stored procedure's parameter values.</param>
2207         /// <returns>A SqlDataReader containing the resultset generated by the command</returns>
2208         public static SqlDataReader ExecuteReaderTypedParams(SqlTransaction transaction, String spName, DataRow dataRow)
2209         {
2210             if( transaction == null ) throw new ArgumentNullException( "transaction" );
2211             if( transaction != null && transaction.Connection == null ) throw new ArgumentException( "The transaction was rollbacked or commited, please provide an open transaction.", "transaction" );
2212             if( spName == null || spName.Length == 0 ) throw new ArgumentNullException( "spName" );
2213 
2214             // If the row has values, the store procedure parameters must be initialized
2215             if( dataRow != null && dataRow.ItemArray.Length > 0 )
2216             {
2217                 // Pull the parameters for this stored procedure from the parameter cache (or discover them & populate the cache)
2218                 SqlParameter[] commandParameters = SqlHelperParameterCache.GetSpParameterSet(transaction.Connection, spName);
2219                 
2220                 // Set the parameters values
2221                 AssignParameterValues(commandParameters, dataRow);
2222                 
2223                 return SqlHelper.ExecuteReader(transaction, CommandType.StoredProcedure, spName, commandParameters);
2224             }
2225             else
2226             {
2227                 return SqlHelper.ExecuteReader(transaction, CommandType.StoredProcedure, spName);
2228             }
2229         }
2230         #endregion
2231 
2232         #region ExecuteScalarTypedParams
2233         /// <summary>
2234         /// Execute a stored procedure via a SqlCommand (that returns a 1x1 resultset) against the database specified in 
2235         /// the connection string using the dataRow column values as the stored procedure's parameters values.
2236         /// This method will query the database to discover the parameters for the 
2237         /// stored procedure (the first time each stored procedure is called), and assign the values based on parameter order.
2238         /// </summary>
2239         /// <param name="connectionString">A valid connection string for a SqlConnection</param>
2240         /// <param name="spName">The name of the stored procedure</param>
2241         /// <param name="dataRow">The dataRow used to hold the stored procedure's parameter values.</param>
2242         /// <returns>An object containing the value in the 1x1 resultset generated by the command</returns>
2243         public static object ExecuteScalarTypedParams(String connectionString, String spName, DataRow dataRow)
2244         {
2245             if( connectionString == null || connectionString.Length == 0 ) throw new ArgumentNullException( "connectionString" );
2246             if( spName == null || spName.Length == 0 ) throw new ArgumentNullException( "spName" );
2247             
2248             // If the row has values, the store procedure parameters must be initialized
2249             if( dataRow != null && dataRow.ItemArray.Length > 0)
2250             {
2251                 // Pull the parameters for this stored procedure from the parameter cache (or discover them & populate the cache)
2252                 SqlParameter[] commandParameters = SqlHelperParameterCache.GetSpParameterSet(connectionString, spName);
2253                 
2254                 // Set the parameters values
2255                 AssignParameterValues(commandParameters, dataRow);
2256                 
2257                 return SqlHelper.ExecuteScalar(connectionString, CommandType.StoredProcedure, spName, commandParameters);
2258             }
2259             else
2260             {
2261                 return SqlHelper.ExecuteScalar(connectionString, CommandType.StoredProcedure, spName);
2262             }
2263         }
2264 
2265         /// <summary>
2266         /// Execute a stored procedure via a SqlCommand (that returns a 1x1 resultset) against the specified SqlConnection 
2267         /// using the dataRow column values as the stored procedure's parameters values.
2268         /// This method will query the database to discover the parameters for the 
2269         /// stored procedure (the first time each stored procedure is called), and assign the values based on parameter order.
2270         /// </summary>
2271         /// <param name="connection">A valid SqlConnection object</param>
2272         /// <param name="spName">The name of the stored procedure</param>
2273         /// <param name="dataRow">The dataRow used to hold the stored procedure's parameter values.</param>
2274         /// <returns>An object containing the value in the 1x1 resultset generated by the command</returns>
2275         public static object ExecuteScalarTypedParams(SqlConnection connection, String spName, DataRow dataRow)
2276         {
2277             if( connection == null ) throw new ArgumentNullException( "connection" );
2278             if( spName == null || spName.Length == 0 ) throw new ArgumentNullException( "spName" );
2279 
2280             // If the row has values, the store procedure parameters must be initialized
2281             if( dataRow != null && dataRow.ItemArray.Length > 0)
2282             {
2283                 // Pull the parameters for this stored procedure from the parameter cache (or discover them & populate the cache)
2284                 SqlParameter[] commandParameters = SqlHelperParameterCache.GetSpParameterSet(connection, spName);
2285                 
2286                 // Set the parameters values
2287                 AssignParameterValues(commandParameters, dataRow);
2288                 
2289                 return SqlHelper.ExecuteScalar(connection, CommandType.StoredProcedure, spName, commandParameters);
2290             }
2291             else
2292             {
2293                 return SqlHelper.ExecuteScalar(connection, CommandType.StoredProcedure, spName);
2294             }
2295         }
2296 
2297         /// <summary>
2298         /// Execute a stored procedure via a SqlCommand (that returns a 1x1 resultset) against the specified SqlTransaction
2299         /// using the dataRow column values as the stored procedure's parameters values.
2300         /// This method will query the database to discover the parameters for the 
2301         /// stored procedure (the first time each stored procedure is called), and assign the values based on parameter order.
2302         /// </summary>
2303         /// <param name="transaction">A valid SqlTransaction object</param>
2304         /// <param name="spName">The name of the stored procedure</param>
2305         /// <param name="dataRow">The dataRow used to hold the stored procedure's parameter values.</param>
2306         /// <returns>An object containing the value in the 1x1 resultset generated by the command</returns>
2307         public static object ExecuteScalarTypedParams(SqlTransaction transaction, String spName, DataRow dataRow)
2308         {
2309             if( transaction == null ) throw new ArgumentNullException( "transaction" );
2310             if( transaction != null && transaction.Connection == null ) throw new ArgumentException( "The transaction was rollbacked or commited, please provide an open transaction.", "transaction" );
2311             if( spName == null || spName.Length == 0 ) throw new ArgumentNullException( "spName" );
2312 
2313             // If the row has values, the store procedure parameters must be initialized
2314             if( dataRow != null && dataRow.ItemArray.Length > 0)
2315             {
2316                 // Pull the parameters for this stored procedure from the parameter cache (or discover them & populate the cache)
2317                 SqlParameter[] commandParameters = SqlHelperParameterCache.GetSpParameterSet(transaction.Connection, spName);
2318                 
2319                 // Set the parameters values
2320                 AssignParameterValues(commandParameters, dataRow);
2321                 
2322                 return SqlHelper.ExecuteScalar(transaction, CommandType.StoredProcedure, spName, commandParameters);
2323             }
2324             else
2325             {
2326                 return SqlHelper.ExecuteScalar(transaction, CommandType.StoredProcedure, spName);
2327             }
2328         }
2329         #endregion
2330 
2331         #region ExecuteXmlReaderTypedParams
2332         /// <summary>
2333         /// Execute a stored procedure via a SqlCommand (that returns a resultset) against the specified SqlConnection 
2334         /// using the dataRow column values as the stored procedure's parameters values.
2335         /// This method will query the database to discover the parameters for the 
2336         /// stored procedure (the first time each stored procedure is called), and assign the values based on parameter order.
2337         /// </summary>
2338         /// <param name="connection">A valid SqlConnection object</param>
2339         /// <param name="spName">The name of the stored procedure</param>
2340         /// <param name="dataRow">The dataRow used to hold the stored procedure's parameter values.</param>
2341         /// <returns>An XmlReader containing the resultset generated by the command</returns>
2342         public static XmlReader ExecuteXmlReaderTypedParams(SqlConnection connection, String spName, DataRow dataRow)
2343         {
2344             if( connection == null ) throw new ArgumentNullException( "connection" );
2345             if( spName == null || spName.Length == 0 ) throw new ArgumentNullException( "spName" );
2346 
2347             // If the row has values, the store procedure parameters must be initialized
2348             if( dataRow != null && dataRow.ItemArray.Length > 0)
2349             {
2350                 // Pull the parameters for this stored procedure from the parameter cache (or discover them & populate the cache)
2351                 SqlParameter[] commandParameters = SqlHelperParameterCache.GetSpParameterSet(connection, spName);
2352                 
2353                 // Set the parameters values
2354                 AssignParameterValues(commandParameters, dataRow);
2355                 
2356                 return SqlHelper.ExecuteXmlReader(connection, CommandType.StoredProcedure, spName, commandParameters);
2357             }
2358             else
2359             {
2360                 return SqlHelper.ExecuteXmlReader(connection, CommandType.StoredProcedure, spName);
2361             }
2362         }
2363 
2364         /// <summary>
2365         /// Execute a stored procedure via a SqlCommand (that returns a resultset) against the specified SqlTransaction 
2366         /// using the dataRow column values as the stored procedure's parameters values.
2367         /// This method will query the database to discover the parameters for the 
2368         /// stored procedure (the first time each stored procedure is called), and assign the values based on parameter order.
2369         /// </summary>
2370         /// <param name="transaction">A valid SqlTransaction object</param>
2371         /// <param name="spName">The name of the stored procedure</param>
2372         /// <param name="dataRow">The dataRow used to hold the stored procedure's parameter values.</param>
2373         /// <returns>An XmlReader containing the resultset generated by the command</returns>
2374         public static XmlReader ExecuteXmlReaderTypedParams(SqlTransaction transaction, String spName, DataRow dataRow)
2375         {
2376             if( transaction == null ) throw new ArgumentNullException( "transaction" );
2377             if( transaction != null && transaction.Connection == null ) throw new ArgumentException( "The transaction was rollbacked or commited, please provide an open transaction.", "transaction" );
2378             if( spName == null || spName.Length == 0 ) throw new ArgumentNullException( "spName" );
2379 
2380             // If the row has values, the store procedure parameters must be initialized
2381             if( dataRow != null && dataRow.ItemArray.Length > 0)
2382             {
2383                 // Pull the parameters for this stored procedure from the parameter cache (or discover them & populate the cache)
2384                 SqlParameter[] commandParameters = SqlHelperParameterCache.GetSpParameterSet(transaction.Connection, spName);
2385                 
2386                 // Set the parameters values
2387                 AssignParameterValues(commandParameters, dataRow);
2388                 
2389                 return SqlHelper.ExecuteXmlReader(transaction, CommandType.StoredProcedure, spName, commandParameters);
2390             }
2391             else
2392             {
2393                 return SqlHelper.ExecuteXmlReader(transaction, CommandType.StoredProcedure, spName);
2394             }
2395         }
2396         #endregion
2397 
2398     }
2399 
2400     /// <summary>
2401     /// SqlHelperParameterCache provides functions to leverage a static cache of procedure parameters, and the
2402     /// ability to discover parameters for stored procedures at run-time.
2403     /// </summary>
2404     public sealed class SqlHelperParameterCache
2405     {
2406         #region private methods, variables, and constructors
2407 
2408         //Since this class provides only static methods, make the default constructor private to prevent 
2409         //instances from being created with "new SqlHelperParameterCache()"
2410         private SqlHelperParameterCache() {}
2411 
2412         private static Hashtable paramCache = Hashtable.Synchronized(new Hashtable());
2413 
2414         /// <summary>
2415         /// Resolve at run time the appropriate set of SqlParameters for a stored procedure
2416         /// </summary>
2417         /// <param name="connection">A valid SqlConnection object</param>
2418         /// <param name="spName">The name of the stored procedure</param>
2419         /// <param name="includeReturnValueParameter">Whether or not to include their return value parameter</param>
2420         /// <returns>The parameter array discovered.</returns>
2421         private static SqlParameter[] DiscoverSpParameterSet(SqlConnection connection, string spName, bool includeReturnValueParameter)
2422         {
2423             if( connection == null ) throw new ArgumentNullException( "connection" );
2424             if( spName == null || spName.Length == 0 ) throw new ArgumentNullException( "spName" );
2425 
2426             SqlCommand cmd = new SqlCommand(spName, connection);
2427             cmd.CommandType = CommandType.StoredProcedure;
2428 
2429             connection.Open();
2430             SqlCommandBuilder.DeriveParameters(cmd);
2431             connection.Close();
2432 
2433             if (!includeReturnValueParameter) 
2434             {
2435                 cmd.Parameters.RemoveAt(0);
2436             }
2437                 
2438             SqlParameter[] discoveredParameters = new SqlParameter[cmd.Parameters.Count];
2439 
2440             cmd.Parameters.CopyTo(discoveredParameters, 0);
2441 
2442             // Init the parameters with a DBNull value
2443             foreach (SqlParameter discoveredParameter in discoveredParameters)
2444             {
2445                 discoveredParameter.Value = DBNull.Value;
2446             }
2447             return discoveredParameters;
2448         }
2449 
2450         /// <summary>
2451         /// Deep copy of cached SqlParameter array
2452         /// </summary>
2453         /// <param name="originalParameters"></param>
2454         /// <returns></returns>
2455         private static SqlParameter[] CloneParameters(SqlParameter[] originalParameters)
2456         {
2457             SqlParameter[] clonedParameters = new SqlParameter[originalParameters.Length];
2458 
2459             for (int i = 0, j = originalParameters.Length; i < j; i++)
2460             {
2461                 clonedParameters[i] = (SqlParameter)((ICloneable)originalParameters[i]).Clone();
2462             }
2463 
2464             return clonedParameters;
2465         }
2466 
2467         #endregion private methods, variables, and constructors
2468 
2469         #region caching functions
2470 
2471         /// <summary>
2472         /// Add parameter array to the cache
2473         /// </summary>
2474         /// <param name="connectionString">A valid connection string for a SqlConnection</param>
2475         /// <param name="commandText">The stored procedure name or T-SQL command</param>
2476         /// <param name="commandParameters">An array of SqlParamters to be cached</param>
2477         public static void CacheParameterSet(string connectionString, string commandText, params SqlParameter[] commandParameters)
2478         {
2479             if( connectionString == null || connectionString.Length == 0 ) throw new ArgumentNullException( "connectionString" );
2480             if( commandText == null || commandText.Length == 0 ) throw new ArgumentNullException( "commandText" );
2481 
2482             string hashKey = connectionString + ":" + commandText;
2483 
2484             paramCache[hashKey] = commandParameters;
2485         }
2486 
2487         /// <summary>
2488         /// Retrieve a parameter array from the cache
2489         /// </summary>
2490         /// <param name="connectionString">A valid connection string for a SqlConnection</param>
2491         /// <param name="commandText">The stored procedure name or T-SQL command</param>
2492         /// <returns>An array of SqlParamters</returns>
2493         public static SqlParameter[] GetCachedParameterSet(string connectionString, string commandText)
2494         {
2495             if( connectionString == null || connectionString.Length == 0 ) throw new ArgumentNullException( "connectionString" );
2496             if( commandText == null || commandText.Length == 0 ) throw new ArgumentNullException( "commandText" );
2497 
2498             string hashKey = connectionString + ":" + commandText;
2499 
2500             SqlParameter[] cachedParameters = paramCache[hashKey] as SqlParameter[];
2501             if (cachedParameters == null)
2502             {            
2503                 return null;
2504             }
2505             else
2506             {
2507                 return CloneParameters(cachedParameters);
2508             }
2509         }
2510 
2511         #endregion caching functions
2512 
2513         #region Parameter Discovery Functions
2514 
2515         /// <summary>
2516         /// Retrieves the set of SqlParameters appropriate for the stored procedure
2517         /// </summary>
2518         /// <remarks>
2519         /// This method will query the database for this information, and then store it in a cache for future requests.
2520         /// </remarks>
2521         /// <param name="connectionString">A valid connection string for a SqlConnection</param>
2522         /// <param name="spName">The name of the stored procedure</param>
2523         /// <returns>An array of SqlParameters</returns>
2524         public static SqlParameter[] GetSpParameterSet(string connectionString, string spName)
2525         {
2526             return GetSpParameterSet(connectionString, spName, false);
2527         }
2528 
2529         /// <summary>
2530         /// Retrieves the set of SqlParameters appropriate for the stored procedure
2531         /// </summary>
2532         /// <remarks>
2533         /// This method will query the database for this information, and then store it in a cache for future requests.
2534         /// </remarks>
2535         /// <param name="connectionString">A valid connection string for a SqlConnection</param>
2536         /// <param name="spName">The name of the stored procedure</param>
2537         /// <param name="includeReturnValueParameter">A bool value indicating whether the return value parameter should be included in the results</param>
2538         /// <returns>An array of SqlParameters</returns>
2539         public static SqlParameter[] GetSpParameterSet(string connectionString, string spName, bool includeReturnValueParameter)
2540         {
2541             if( connectionString == null || connectionString.Length == 0 ) throw new ArgumentNullException( "connectionString" );
2542             if( spName == null || spName.Length == 0 ) throw new ArgumentNullException( "spName" );
2543 
2544             using(SqlConnection connection = new SqlConnection(connectionString))
2545             {
2546                 return GetSpParameterSetInternal(connection, spName, includeReturnValueParameter);
2547             }
2548         }
2549 
2550         /// <summary>
2551         /// Retrieves the set of SqlParameters appropriate for the stored procedure
2552         /// </summary>
2553         /// <remarks>
2554         /// This method will query the database for this information, and then store it in a cache for future requests.
2555         /// </remarks>
2556         /// <param name="connection">A valid SqlConnection object</param>
2557         /// <param name="spName">The name of the stored procedure</param>
2558         /// <returns>An array of SqlParameters</returns>
2559         internal static SqlParameter[] GetSpParameterSet(SqlConnection connection, string spName)
2560         {
2561             return GetSpParameterSet(connection, spName, false);
2562         }
2563 
2564         /// <summary>
2565         /// Retrieves the set of SqlParameters appropriate for the stored procedure
2566         /// </summary>
2567         /// <remarks>
2568         /// This method will query the database for this information, and then store it in a cache for future requests.
2569         /// </remarks>
2570         /// <param name="connection">A valid SqlConnection object</param>
2571         /// <param name="spName">The name of the stored procedure</param>
2572         /// <param name="includeReturnValueParameter">A bool value indicating whether the return value parameter should be included in the results</param>
2573         /// <returns>An array of SqlParameters</returns>
2574         internal static SqlParameter[] GetSpParameterSet(SqlConnection connection, string spName, bool includeReturnValueParameter)
2575         {
2576             if( connection == null ) throw new ArgumentNullException( "connection" );
2577             using (SqlConnection clonedConnection = (SqlConnection)((ICloneable)connection).Clone())
2578             {
2579                 return GetSpParameterSetInternal(clonedConnection, spName, includeReturnValueParameter);
2580             }
2581         }
2582 
2583         /// <summary>
2584         /// Retrieves the set of SqlParameters appropriate for the stored procedure
2585         /// </summary>
2586         /// <param name="connection">A valid SqlConnection object</param>
2587         /// <param name="spName">The name of the stored procedure</param>
2588         /// <param name="includeReturnValueParameter">A bool value indicating whether the return value parameter should be included in the results</param>
2589         /// <returns>An array of SqlParameters</returns>
2590         private static SqlParameter[] GetSpParameterSetInternal(SqlConnection connection, string spName, bool includeReturnValueParameter)
2591         {
2592             if( connection == null ) throw new ArgumentNullException( "connection" );
2593             if( spName == null || spName.Length == 0 ) throw new ArgumentNullException( "spName" );
2594 
2595             string hashKey = connection.ConnectionString + ":" + spName + (includeReturnValueParameter ? ":include ReturnValue Parameter":"");
2596 
2597             SqlParameter[] cachedParameters;
2598             
2599             cachedParameters = paramCache[hashKey] as SqlParameter[];
2600             if (cachedParameters == null)
2601             {    
2602                 SqlParameter[] spParameters = DiscoverSpParameterSet(connection, spName, includeReturnValueParameter);
2603                 paramCache[hashKey] = spParameters;
2604                 cachedParameters = spParameters;
2605             }
2606             
2607             return CloneParameters(cachedParameters);
2608         }
2609         /// <summary>
2610         /// 清空缓存参数
2611         /// </summary>
2612         public static void  ClearCache()
2613         {
2614             paramCache.Clear();
2615         }
2616         #endregion Parameter Discovery Functions
2617 
2618     }
2619 }
View Code

 

posted @ 2015-07-03 09:40  银河系上的地球  阅读(197)  评论(0编辑  收藏  举报