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