ASP.Net2.0 SQL数据访问模块(SqlHelper For MSSQL)

  1. using System;
  2. using System.Data;
  3. using System.Xml;
  4. using System.Data.SqlClient;
  5. using System.Collections;
  6. namespace SqlHelper
  7. {
  8.     /// <summary>
  9.     /// The SqlHelper class is intended to encapsulate high performance, scalable best practices for 
  10.     /// common uses of SqlClient.
  11.     /// </summary>
  12.     public sealed class SqlHelper
  13.     {
  14.         /// <summary>
  15.         /// Database connection strings
  16.         /// </summary>
  17.         public static string ConnStr ; 
  18.         
  19.         #region private utility methods & constructors
  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.         /// <summary>
  24.         /// This method is used to attach array of SqlParameters to a SqlCommand.
  25.         /// 
  26.         /// This method will assign a value of DbNull to any parameter with a direction of
  27.         /// InputOutput and a value of null.  
  28.         /// 
  29.         /// This behavior will prevent default values from being used, but
  30.         /// this will be the less common case than an intended pure output parameter (derived as InputOutput)
  31.         /// where the user provided no input value.
  32.         /// </summary>
  33.         /// <param name="command">The command to which the parameters will be added</param>
  34.         /// <param name="commandParameters">an array of SqlParameters tho be added to command</param>
  35.         private static void AttachParameters(SqlCommand command, SqlParameter[] commandParameters)
  36.         {
  37.             foreach (SqlParameter p in commandParameters)
  38.             {
  39.                 //check for derived output value with no value assigned
  40.                 if ((p.Direction == ParameterDirection.InputOutput) && (p.Value == null))
  41.                 {
  42.                     p.Value = DBNull.Value;
  43.                 }
  44.                 command.Parameters.Add(p);
  45.             }
  46.         }
  47.         /// <summary>
  48.         /// This method assigns an array of values to an array of SqlParameters.
  49.         /// </summary>
  50.         /// <param name="commandParameters">array of SqlParameters to be assigned values</param>
  51.         /// <param name="parameterValues">array of objects holding the values to be assigned</param>
  52.         private static void AssignParameterValues(SqlParameter[] commandParameters, object[] parameterValues)
  53.         {
  54.             if ((commandParameters == null) || (parameterValues == null))
  55.             {
  56.                 //do nothing if we get no data
  57.                 return;
  58.             }
  59.             // we must have the same number of values as we pave parameters to put them in
  60.             if (commandParameters.Length != parameterValues.Length)
  61.             {
  62.                 throw new ArgumentException("Parameter count does not match Parameter Value count.");
  63.             }
  64.             //iterate through the SqlParameters, assigning the values from the corresponding position in the 
  65.             //value array
  66.             for (int i = 0, j = commandParameters.Length; i < j; i++)
  67.             {
  68.                 commandParameters[i].Value = parameterValues[i];
  69.             }
  70.         }
  71.         /// <summary>
  72.         /// This method opens (if necessary) and assigns a connection, transaction, command type and parameters 
  73.         /// to the provided command.
  74.         /// </summary>
  75.         /// <param name="command">the SqlCommand to be prepared</param>
  76.         /// <param name="connection">a valid SqlConnection, on which to execute this command</param>
  77.         /// <param name="transaction">a valid SqlTransaction, or 'null'</param>
  78.         /// <param name="commandType">the CommandType (stored procedure, text, etc.)</param>
  79.         /// <param name="commandText">the stored procedure name or T-SQL command</param>
  80.         /// <param name="commandParameters">an array of SqlParameters to be associated with the command or 'null' if no parameters are required</param>
  81.         private static void PrepareCommand(SqlCommand command, SqlConnection connection, SqlTransaction transaction, CommandType commandType, string commandText, SqlParameter[] commandParameters)
  82.         {
  83.             //if the provided connection is not open, we will open it
  84.             if (connection.State != ConnectionState.Open)
  85.             {
  86.                 connection.Open();
  87.             }
  88.             //associate the connection with the command
  89.             command.Connection = connection;
  90.             //set the command text (stored procedure name or SQL statement)
  91.             command.CommandText = commandText;
  92.             //if we were provided a transaction, assign it.
  93.             if (transaction != null)
  94.             {
  95.                 command.Transaction = transaction;
  96.             }
  97.             //set the command type
  98.             command.CommandType = commandType;
  99.             //attach the command parameters if they are provided
  100.             if (commandParameters != null)
  101.             {
  102.                 AttachParameters(command, commandParameters);
  103.             }
  104.             return;
  105.         }
  106.         #endregion private utility methods & constructors
  107.         #region ExecuteNonQuery
  108.         /// <summary>
  109.         /// Execute a SqlCommand (that returns no resultset and takes no parameters) against the database specified in 
  110.         /// the connection string. 
  111.         /// </summary>
  112.         /// <remarks>
  113.         /// e.g.:  
  114.         ///  int result = ExecuteNonQuery(connString, CommandType.StoredProcedure, "PublishOrders");
  115.         /// </remarks>
  116.         /// <param name="connectionString">a valid connection string for a SqlConnection</param>
  117.         /// <param name="commandType">the CommandType (stored procedure, text, etc.)</param>
  118.         /// <param name="commandText">the stored procedure name or T-SQL command</param>
  119.         /// <returns>an int representing the number of rows affected by the command</returns>
  120.         public static int ExecuteNonQuery(string connectionString, CommandType commandType, string commandText)
  121.         {
  122.             //pass through the call providing null for the set of SqlParameters
  123.             return ExecuteNonQuery(connectionString, commandType, commandText, (SqlParameter[])null);
  124.         }
  125.         /// <summary>
  126.         /// Execute a SqlCommand (that returns no resultset) against the database specified in the connection string 
  127.         /// using the provided parameters.
  128.         /// </summary>
  129.         /// <remarks>
  130.         /// e.g.:  
  131.         ///  int result = ExecuteNonQuery(connString, CommandType.StoredProcedure, "PublishOrders", new SqlParameter("@prodid", 24));
  132.         /// </remarks>
  133.         /// <param name="connectionString">a valid connection string for a SqlConnection</param>
  134.         /// <param name="commandType">the CommandType (stored procedure, text, etc.)</param>
  135.         /// <param name="commandText">the stored procedure name or T-SQL command</param>
  136.         /// <param name="commandParameters">an array of SqlParamters used to execute the command</param>
  137.         /// <returns>an int representing the number of rows affected by the command</returns>
  138.         public static int ExecuteNonQuery(string connectionString, CommandType commandType, string commandText, params SqlParameter[] commandParameters)
  139.         {
  140.             //create & open a SqlConnection, and dispose of it after we are done.
  141.             using (SqlConnection cn = new SqlConnection(connectionString))
  142.             {
  143.                 cn.Open();
  144.                 //call the overload that takes a connection in place of the connection string
  145.                 return ExecuteNonQuery(cn, commandType, commandText, commandParameters);
  146.             }
  147.         }
  148.         /// <summary>
  149.         /// Execute a stored procedure via a SqlCommand (that returns no resultset) against the database specified in 
  150.         /// the connection string using the provided parameter values.  This method will query the database to discover the parameters for the 
  151.         /// stored procedure (the first time each stored procedure is called), and assign the values based on parameter order.
  152.         /// </summary>
  153.         /// <remarks>
  154.         /// This method provides no access to output parameters or the stored procedure's return value parameter.
  155.         /// 
  156.         /// e.g.:  
  157.         ///  int result = ExecuteNonQuery(connString, "PublishOrders", 24, 36);
  158.         /// </remarks>
  159.         /// <param name="connectionString">a valid connection string for a SqlConnection</param>
  160.         /// <param name="spName">the name of the stored prcedure</param>
  161.         /// <param name="parameterValues">an array of objects to be assigned as the input values of the stored procedure</param>
  162.         /// <returns>an int representing the number of rows affected by the command</returns>
  163.         public static int ExecuteNonQuery(string connectionString, string spName, params object[] parameterValues)
  164.         {
  165.             //if we receive parameter values, we need to figure out where they go
  166.             if ((parameterValues != null) && (parameterValues.Length > 0))
  167.             {
  168.                 //pull the parameters for this stored procedure from the parameter cache (or discover them & populate the cache)
  169.                 SqlParameter[] commandParameters = SqlHelperParameterCache.GetSpParameterSet(connectionString, spName);
  170.                 //assign the provided values to these parameters based on parameter order
  171.                 AssignParameterValues(commandParameters, parameterValues);
  172.                 //call the overload that takes an array of SqlParameters
  173.                 return ExecuteNonQuery(connectionString, CommandType.StoredProcedure, spName, commandParameters);
  174.             }
  175.             //otherwise we can just call the SP without params
  176.             else
  177.             {
  178.                 return ExecuteNonQuery(connectionString, CommandType.StoredProcedure, spName);
  179.             }
  180.         }
  181.         /// <summary>
  182.         /// Execute a SqlCommand (that returns no resultset and takes no parameters) against the provided SqlConnection. 
  183.         /// </summary>
  184.         /// <remarks>
  185.         /// e.g.:  
  186.         ///  int result = ExecuteNonQuery(conn, CommandType.StoredProcedure, "PublishOrders");
  187.         /// </remarks>
  188.         /// <param name="connection">a valid SqlConnection</param>
  189.         /// <param name="commandType">the CommandType (stored procedure, text, etc.)</param>
  190.         /// <param name="commandText">the stored procedure name or T-SQL command</param>
  191.         /// <returns>an int representing the number of rows affected by the command</returns>
  192.         public static int ExecuteNonQuery(SqlConnection connection, CommandType commandType, string commandText)
  193.         {
  194.             //pass through the call providing null for the set of SqlParameters
  195.             return ExecuteNonQuery(connection, commandType, commandText, (SqlParameter[])null);
  196.         }
  197.         /// <summary>
  198.         /// Execute a SqlCommand (that returns no resultset) against the specified SqlConnection 
  199.         /// using the provided parameters.
  200.         /// </summary>
  201.         /// <remarks>
  202.         /// e.g.:  
  203.         ///  int result = ExecuteNonQuery(conn, CommandType.StoredProcedure, "PublishOrders", new SqlParameter("@prodid", 24));
  204.         /// </remarks>
  205.         /// <param name="connection">a valid SqlConnection</param>
  206.         /// <param name="commandType">the CommandType (stored procedure, text, etc.)</param>
  207.         /// <param name="commandText">the stored procedure name or T-SQL command</param>
  208.         /// <param name="commandParameters">an array of SqlParamters used to execute the command</param>
  209.         /// <returns>an int representing the number of rows affected by the command</returns>
  210.         public static int ExecuteNonQuery(SqlConnection connection, CommandType commandType, string commandText, params SqlParameter[] commandParameters)
  211.         {
  212.             //create a command and prepare it for execution
  213.             SqlCommand cmd = new SqlCommand();
  214.             PrepareCommand(cmd, connection, (SqlTransaction)null, commandType, commandText, commandParameters);
  215.             //finally, execute the command.
  216.             int retval = cmd.ExecuteNonQuery();
  217.             // detach the SqlParameters from the command object, so they can be used again.
  218.             cmd.Parameters.Clear();
  219.             return retval;
  220.         }
  221.         /// <summary>
  222.         /// Execute a stored procedure via a SqlCommand (that returns no resultset) against the specified SqlConnection 
  223.         /// using the provided parameter values.  This method will query the database to discover the parameters for the 
  224.         /// stored procedure (the first time each stored procedure is called), and assign the values based on parameter order.
  225.         /// </summary>
  226.         /// <remarks>
  227.         /// This method provides no access to output parameters or the stored procedure's return value parameter.
  228.         /// 
  229.         /// e.g.:  
  230.         ///  int result = ExecuteNonQuery(conn, "PublishOrders", 24, 36);
  231.         /// </remarks>
  232.         /// <param name="connection">a valid SqlConnection</param>
  233.         /// <param name="spName">the name of the stored procedure</param>
  234.         /// <param name="parameterValues">an array of objects to be assigned as the input values of the stored procedure</param>
  235.         /// <returns>an int representing the number of rows affected by the command</returns>
  236.         public static int ExecuteNonQuery(SqlConnection connection, string spName, params object[] parameterValues)
  237.         {
  238.             //if we receive parameter values, we need to figure out where they go
  239.             if ((parameterValues != null) && (parameterValues.Length > 0))
  240.             {
  241.                 //pull the parameters for this stored procedure from the parameter cache (or discover them & populate the cache)
  242.                 SqlParameter[] commandParameters = SqlHelperParameterCache.GetSpParameterSet(connection.ConnectionString, spName);
  243.                 //assign the provided values to these parameters based on parameter order
  244.                 AssignParameterValues(commandParameters, parameterValues);
  245.                 //call the overload that takes an array of SqlParameters
  246.                 return ExecuteNonQuery(connection, CommandType.StoredProcedure, spName, commandParameters);
  247.             }
  248.             //otherwise we can just call the SP without params
  249.             else
  250.             {
  251.                 return ExecuteNonQuery(connection, CommandType.StoredProcedure, spName);
  252.             }
  253.         }
  254.         /// <summary>
  255.         /// Execute a SqlCommand (that returns no resultset and takes no parameters) against the provided SqlTransaction. 
  256.         /// </summary>
  257.         /// <remarks>
  258.         /// e.g.:  
  259.         ///  int result = ExecuteNonQuery(trans, CommandType.StoredProcedure, "PublishOrders");
  260.         /// </remarks>
  261.         /// <param name="transaction">a valid SqlTransaction</param>
  262.         /// <param name="commandType">the CommandType (stored procedure, text, etc.)</param>
  263.         /// <param name="commandText">the stored procedure name or T-SQL command</param>
  264.         /// <returns>an int representing the number of rows affected by the command</returns>
  265.         public static int ExecuteNonQuery(SqlTransaction transaction, CommandType commandType, string commandText)
  266.         {
  267.             //pass through the call providing null for the set of SqlParameters
  268.             return ExecuteNonQuery(transaction, commandType, commandText, (SqlParameter[])null);
  269.         }
  270.         /// <summary>
  271.         /// Execute a SqlCommand (that returns no resultset) against the specified SqlTransaction
  272.         /// using the provided parameters.
  273.         /// </summary>
  274.         /// <remarks>
  275.         /// e.g.:  
  276.         ///  int result = ExecuteNonQuery(trans, CommandType.StoredProcedure, "GetOrders", new SqlParameter("@prodid", 24));
  277.         /// </remarks>
  278.         /// <param name="transaction">a valid SqlTransaction</param>
  279.         /// <param name="commandType">the CommandType (stored procedure, text, etc.)</param>
  280.         /// <param name="commandText">the stored procedure name or T-SQL command</param>
  281.         /// <param name="commandParameters">an array of SqlParamters used to execute the command</param>
  282.         /// <returns>an int representing the number of rows affected by the command</returns>
  283.         public static int ExecuteNonQuery(SqlTransaction transaction, CommandType commandType, string commandText, params SqlParameter[] commandParameters)
  284.         {
  285.             //create a command and prepare it for execution
  286.             SqlCommand cmd = new SqlCommand();
  287.             PrepareCommand(cmd, transaction.Connection, transaction, commandType, commandText, commandParameters);
  288.             //finally, execute the command.
  289.             int retval = cmd.ExecuteNonQuery();
  290.             // detach the SqlParameters from the command object, so they can be used again.
  291.             cmd.Parameters.Clear();
  292.             return retval;
  293.         }
  294.         /// <summary>
  295.         /// Execute a stored procedure via a SqlCommand (that returns no resultset) against the specified 
  296.         /// SqlTransaction using the provided parameter values.  This method will query the database to discover the parameters for the 
  297.         /// stored procedure (the first time each stored procedure is called), and assign the values based on parameter order.
  298.         /// </summary>
  299.         /// <remarks>
  300.         /// This method provides no access to output parameters or the stored procedure's return value parameter.
  301.         /// 
  302.         /// e.g.:  
  303.         ///  int result = ExecuteNonQuery(conn, trans, "PublishOrders", 24, 36);
  304.         /// </remarks>
  305.         /// <param name="transaction">a valid SqlTransaction</param>
  306.         /// <param name="spName">the name of the stored procedure</param>
  307.         /// <param name="parameterValues">an array of objects to be assigned as the input values of the stored procedure</param>
  308.         /// <returns>an int representing the number of rows affected by the command</returns>
  309.         public static int ExecuteNonQuery(SqlTransaction transaction, string spName, params object[] parameterValues)
  310.         {
  311.             //if we receive parameter values, we need to figure out where they go
  312.             if ((parameterValues != null) && (parameterValues.Length > 0))
  313.             {
  314.                 //pull the parameters for this stored procedure from the parameter cache (or discover them & populate the cache)
  315.                 SqlParameter[] commandParameters = SqlHelperParameterCache.GetSpParameterSet(transaction.Connection.ConnectionString, spName);
  316.                 //assign the provided values to these parameters based on parameter order
  317.                 AssignParameterValues(commandParameters, parameterValues);
  318.                 //call the overload that takes an array of SqlParameters
  319.                 return ExecuteNonQuery(transaction, CommandType.StoredProcedure, spName, commandParameters);
  320.             }
  321.             //otherwise we can just call the SP without params
  322.             else
  323.             {
  324.                 return ExecuteNonQuery(transaction, CommandType.StoredProcedure, spName);
  325.             }
  326.         }
  327.         #endregion ExecuteNonQuery
  328.         #region ExecuteDataSet
  329.         /// <summary>
  330.         /// Execute a SqlCommand (that returns a resultset and takes no parameters) against the database specified in 
  331.         /// the connection string. 
  332.         /// </summary>
  333.         /// <remarks>
  334.         /// e.g.:  
  335.         ///  DataSet ds = ExecuteDataset(connString, CommandType.StoredProcedure, "GetOrders");
  336.         /// </remarks>
  337.         /// <param name="connectionString">a valid connection string for a SqlConnection</param>
  338.         /// <param name="commandType">the CommandType (stored procedure, text, etc.)</param>
  339.         /// <param name="commandText">the stored procedure name or T-SQL command</param>
  340.         /// <returns>a dataset containing the resultset generated by the command</returns>
  341.         public static DataSet ExecuteDataset(string connectionString, CommandType commandType, string commandText)
  342.         {
  343.             //pass through the call providing null for the set of SqlParameters
  344.             return ExecuteDataset(connectionString, commandType, commandText, (SqlParameter[])null);
  345.         }
  346.         /// <summary>
  347.         /// Execute a SqlCommand (that returns a resultset) against the database specified in the connection string 
  348.         /// using the provided parameters.
  349.         /// </summary>
  350.         /// <remarks>
  351.         /// e.g.:  
  352.         ///  DataSet ds = ExecuteDataset(connString, CommandType.StoredProcedure, "GetOrders", new SqlParameter("@prodid", 24));
  353.         /// </remarks>
  354.         /// <param name="connectionString">a valid connection string for a SqlConnection</param>
  355.         /// <param name="commandType">the CommandType (stored procedure, text, etc.)</param>
  356.         /// <param name="commandText">the stored procedure name or T-SQL command</param>
  357.         /// <param name="commandParameters">an array of SqlParamters used to execute the command</param>
  358.         /// <returns>a dataset containing the resultset generated by the command</returns>
  359.         public static DataSet ExecuteDataset(string connectionString, CommandType commandType, string commandText, params SqlParameter[] commandParameters)
  360.         {
  361.             //create & open a SqlConnection, and dispose of it after we are done.
  362.             using (SqlConnection cn = new SqlConnection(connectionString))
  363.             {
  364.                 cn.Open();
  365.                 //call the overload that takes a connection in place of the connection string
  366.                 return ExecuteDataset(cn, commandType, commandText, commandParameters);
  367.             }
  368.         }
  369.         /// <summary>
  370.         /// Execute a stored procedure via a SqlCommand (that returns a resultset) against the database specified in 
  371.         /// the connection string using the provided parameter values.  This method will query the database to discover the parameters for the 
  372.         /// stored procedure (the first time each stored procedure is called), and assign the values based on parameter order.
  373.         /// </summary>
  374.         /// <remarks>
  375.         /// This method provides no access to output parameters or the stored procedure's return value parameter.
  376.         /// 
  377.         /// e.g.:  
  378.         ///  DataSet ds = ExecuteDataset(connString, "GetOrders", 24, 36);
  379.         /// </remarks>
  380.         /// <param name="connectionString">a valid connection string for a SqlConnection</param>
  381.         /// <param name="spName">the name of the stored procedure</param>
  382.         /// <param name="parameterValues">an array of objects to be assigned as the input values of the stored procedure</param>
  383.         /// <returns>a dataset containing the resultset generated by the command</returns>
  384.         public static DataSet ExecuteDataset(string connectionString, string spName, params object[] parameterValues)
  385.         {
  386.             //if we receive parameter values, we need to figure out where they go
  387.             if ((parameterValues != null) && (parameterValues.Length > 0))
  388.             {
  389.                 //pull the parameters for this stored procedure from the parameter cache (or discover them & populate the cache)
  390.                 SqlParameter[] commandParameters = SqlHelperParameterCache.GetSpParameterSet(connectionString, spName);
  391.                 //assign the provided values to these parameters based on parameter order
  392.                 AssignParameterValues(commandParameters, parameterValues);
  393.                 //call the overload that takes an array of SqlParameters
  394.                 return ExecuteDataset(connectionString, CommandType.StoredProcedure, spName, commandParameters);
  395.             }
  396.             //otherwise we can just call the SP without params
  397.             else
  398.             {
  399.                 return ExecuteDataset(connectionString, CommandType.StoredProcedure, spName);
  400.             }
  401.         }
  402.         /// <summary>
  403.         /// Execute a SqlCommand (that returns a resultset and takes no parameters) against the provided SqlConnection. 
  404.         /// </summary>
  405.         /// <remarks>
  406.         /// e.g.:  
  407.         ///  DataSet ds = ExecuteDataset(conn, CommandType.StoredProcedure, "GetOrders");
  408.         /// </remarks>
  409.         /// <param name="connection">a valid SqlConnection</param>
  410.         /// <param name="commandType">the CommandType (stored procedure, text, etc.)</param>
  411.         /// <param name="commandText">the stored procedure name or T-SQL command</param>
  412.         /// <returns>a dataset containing the resultset generated by the command</returns>
  413.         public static DataSet ExecuteDataset(SqlConnection connection, CommandType commandType, string commandText)
  414.         {
  415.             //pass through the call providing null for the set of SqlParameters
  416.             return ExecuteDataset(connection, commandType, commandText, (SqlParameter[])null);
  417.         }
  418.         /// <summary>
  419.         /// Execute a SqlCommand (that returns a resultset) against the specified SqlConnection 
  420.         /// using the provided parameters.
  421.         /// </summary>
  422.         /// <remarks>
  423.         /// e.g.:  
  424.         ///  DataSet ds = ExecuteDataset(conn, CommandType.StoredProcedure, "GetOrders", new SqlParameter("@prodid", 24));
  425.         /// </remarks>
  426.         /// <param name="connection">a valid SqlConnection</param>
  427.         /// <param name="commandType">the CommandType (stored procedure, text, etc.)</param>
  428.         /// <param name="commandText">the stored procedure name or T-SQL command</param>
  429.         /// <param name="commandParameters">an array of SqlParamters used to execute the command</param>
  430.         /// <returns>a dataset containing the resultset generated by the command</returns>
  431.         public static DataSet ExecuteDataset(SqlConnection connection, CommandType commandType, string commandText, params SqlParameter[] commandParameters)
  432.         {
  433.             //create a command and prepare it for execution
  434.             SqlCommand cmd = new SqlCommand();
  435.             PrepareCommand(cmd, connection, (SqlTransaction)null, commandType, commandText, commandParameters);
  436.             //create the DataAdapter & DataSet
  437.             SqlDataAdapter da = new SqlDataAdapter(cmd);
  438.             DataSet ds = new DataSet();
  439.             //fill the DataSet using default values for DataTable names, etc.
  440.             da.Fill(ds);
  441.             // detach the SqlParameters from the command object, so they can be used again.         
  442.             cmd.Parameters.Clear();
  443.             //return the dataset
  444.             return ds;
  445.         }
  446.         /// <summary>
  447.         /// Execute a stored procedure via a SqlCommand (that returns a resultset) against the specified SqlConnection 
  448.         /// using the provided parameter values.  This method will query the database to discover the parameters for the 
  449.         /// stored procedure (the first time each stored procedure is called), and assign the values based on parameter order.
  450.         /// </summary>
  451.         /// <remarks>
  452.         /// This method provides no access to output parameters or the stored procedure's return value parameter.
  453.         /// 
  454.         /// e.g.:  
  455.         ///  DataSet ds = ExecuteDataset(conn, "GetOrders", 24, 36);
  456.         /// </remarks>
  457.         /// <param name="connection">a valid SqlConnection</param>
  458.         /// <param name="spName">the name of the stored procedure</param>
  459.         /// <param name="parameterValues">an array of objects to be assigned as the input values of the stored procedure</param>
  460.         /// <returns>a dataset containing the resultset generated by the command</returns>
  461.         public static DataSet ExecuteDataset(SqlConnection connection, string spName, params object[] parameterValues)
  462.         {
  463.             //if we receive parameter values, we need to figure out where they go
  464.             if ((parameterValues != null) && (parameterValues.Length > 0))
  465.             {
  466.                 //pull the parameters for this stored procedure from the parameter cache (or discover them & populate the cache)
  467.                 SqlParameter[] commandParameters = SqlHelperParameterCache.GetSpParameterSet(connection.ConnectionString, spName);
  468.                 //assign the provided values to these parameters based on parameter order
  469.                 AssignParameterValues(commandParameters, parameterValues);
  470.                 //call the overload that takes an array of SqlParameters
  471.                 return ExecuteDataset(connection, CommandType.StoredProcedure, spName, commandParameters);
  472.             }
  473.             //otherwise we can just call the SP without params
  474.             else
  475.             {
  476.                 return ExecuteDataset(connection, CommandType.StoredProcedure, spName);
  477.             }
  478.         }
  479.         /// <summary>
  480.         /// Execute a SqlCommand (that returns a resultset and takes no parameters) against the provided SqlTransaction. 
  481.         /// </summary>
  482.         /// <remarks>
  483.         /// e.g.:  
  484.         ///  DataSet ds = ExecuteDataset(trans, CommandType.StoredProcedure, "GetOrders");
  485.         /// </remarks>
  486.         /// <param name="transaction">a valid SqlTransaction</param>
  487.         /// <param name="commandType">the CommandType (stored procedure, text, etc.)</param>
  488.         /// <param name="commandText">the stored procedure name or T-SQL command</param>
  489.         /// <returns>a dataset containing the resultset generated by the command</returns>
  490.         public static DataSet ExecuteDataset(SqlTransaction transaction, CommandType commandType, string commandText)
  491.         {
  492.             //pass through the call providing null for the set of SqlParameters
  493.             return ExecuteDataset(transaction, commandType, commandText, (SqlParameter[])null);
  494.         }
  495.         /// <summary>
  496.         /// Execute a SqlCommand (that returns a resultset) against the specified SqlTransaction
  497.         /// using the provided parameters.
  498.         /// </summary>
  499.         /// <remarks>
  500.         /// e.g.:  
  501.         ///  DataSet ds = ExecuteDataset(trans, CommandType.StoredProcedure, "GetOrders", new SqlParameter("@prodid", 24));
  502.         /// </remarks>
  503.         /// <param name="transaction">a valid SqlTransaction</param>
  504.         /// <param name="commandType">the CommandType (stored procedure, text, etc.)</param>
  505.         /// <param name="commandText">the stored procedure name or T-SQL command</param>
  506.         /// <param name="commandParameters">an array of SqlParamters used to execute the command</param>
  507.         /// <returns>a dataset containing the resultset generated by the command</returns>
  508.         public static DataSet ExecuteDataset(SqlTransaction transaction, CommandType commandType, string commandText, params SqlParameter[] commandParameters)
  509.         {
  510.             //create a command and prepare it for execution
  511.             SqlCommand cmd = new SqlCommand();
  512.             PrepareCommand(cmd, transaction.Connection, transaction, commandType, commandText, commandParameters);
  513.             //create the DataAdapter & DataSet
  514.             SqlDataAdapter da = new SqlDataAdapter(cmd);
  515.             DataSet ds = new DataSet();
  516.             //fill the DataSet using default values for DataTable names, etc.
  517.             da.Fill(ds);
  518.             // detach the SqlParameters from the command object, so they can be used again.
  519.             cmd.Parameters.Clear();
  520.             //return the dataset
  521.             return ds;
  522.         }
  523.         /// <summary>
  524.         /// Execute a stored procedure via a SqlCommand (that returns a resultset) against the specified 
  525.         /// SqlTransaction using the provided parameter values.  This method will query the database to discover the parameters for the 
  526.         /// stored procedure (the first time each stored procedure is called), and assign the values based on parameter order.
  527.         /// </summary>
  528.         /// <remarks>
  529.         /// This method provides no access to output parameters or the stored procedure's return value parameter.
  530.         /// 
  531.         /// e.g.:  
  532.         ///  DataSet ds = ExecuteDataset(trans, "GetOrders", 24, 36);
  533.         /// </remarks>
  534.         /// <param name="transaction">a valid SqlTransaction</param>
  535.         /// <param name="spName">the name of the stored procedure</param>
  536.         /// <param name="parameterValues">an array of objects to be assigned as the input values of the stored procedure</param>
  537.         /// <returns>a dataset containing the resultset generated by the command</returns>
  538.         public static DataSet ExecuteDataset(SqlTransaction transaction, string spName, params object[] parameterValues)
  539.         {
  540.             //if we receive parameter values, we need to figure out where they go
  541.             if ((parameterValues != null) && (parameterValues.Length > 0))
  542.             {
  543.                 //pull the parameters for this stored procedure from the parameter cache (or discover them & populate the cache)
  544.                 SqlParameter[] commandParameters = SqlHelperParameterCache.GetSpParameterSet(transaction.Connection.ConnectionString, spName);
  545.                 //assign the provided values to these parameters based on parameter order
  546.                 AssignParameterValues(commandParameters, parameterValues);
  547.                 //call the overload that takes an array of SqlParameters
  548.                 return ExecuteDataset(transaction, CommandType.StoredProcedure, spName, commandParameters);
  549.             }
  550.             //otherwise we can just call the SP without params
  551.             else
  552.             {
  553.                 return ExecuteDataset(transaction, CommandType.StoredProcedure, spName);
  554.             }
  555.         }
  556.         #endregion ExecuteDataSet
  557.         #region ExecuteReader
  558.         /// <summary>
  559.         /// this enum is used to indicate whether the connection was provided by the caller, or created by SqlHelper, so that
  560.         /// we can set the appropriate CommandBehavior when calling ExecuteReader()
  561.         /// </summary>
  562.         private enum SqlConnectionOwnership
  563.         {
  564.             /// <summary>Connection is owned and managed by SqlHelper</summary>
  565.             Internal,
  566.             /// <summary>Connection is owned and managed by the caller</summary>
  567.             External
  568.         }
  569.         /// <summary>
  570.         /// Create and prepare a SqlCommand, and call ExecuteReader with the appropriate CommandBehavior.
  571.         /// </summary>
  572.         /// <remarks>
  573.         /// If we created and opened the connection, we want the connection to be closed when the DataReader is closed.
  574.         /// 
  575.         /// If the caller provided the connection, we want to leave it to them to manage.
  576.         /// </remarks>
  577.         /// <param name="connection">a valid SqlConnection, on which to execute this command</param>
  578.         /// <param name="transaction">a valid SqlTransaction, or 'null'</param>
  579.         /// <param name="commandType">the CommandType (stored procedure, text, etc.)</param>
  580.         /// <param name="commandText">the stored procedure name or T-SQL command</param>
  581.         /// <param name="commandParameters">an array of SqlParameters to be associated with the command or 'null' if no parameters are required</param>
  582.         /// <param name="connectionOwnership">indicates whether the connection parameter was provided by the caller, or created by SqlHelper</param>
  583.         /// <returns>SqlDataReader containing the results of the command</returns>
  584.         private static SqlDataReader ExecuteReader(SqlConnection connection, SqlTransaction transaction, CommandType commandType, string commandText, SqlParameter[] commandParameters, SqlConnectionOwnership connectionOwnership)
  585.         {
  586.             //create a command and prepare it for execution
  587.             SqlCommand cmd = new SqlCommand();
  588.             PrepareCommand(cmd, connection, transaction, commandType, commandText, commandParameters);
  589.             //create a reader
  590.             SqlDataReader dr;
  591.             // call ExecuteReader with the appropriate CommandBehavior
  592.             if (connectionOwnership == SqlConnectionOwnership.External)
  593.             {
  594.                 dr = cmd.ExecuteReader();
  595.             }
  596.             else
  597.             {
  598.                 dr = cmd.ExecuteReader(CommandBehavior.CloseConnection);
  599.             }
  600.             // detach the SqlParameters from the command object, so they can be used again.
  601.             cmd.Parameters.Clear();
  602.             return dr;
  603.         }
  604.         /// <summary>
  605.         /// Execute a SqlCommand (that returns a resultset and takes no parameters) against the database specified in 
  606.         /// the connection string. 
  607.         /// </summary>
  608.         /// <remarks>
  609.         /// e.g.:  
  610.         ///  SqlDataReader dr = ExecuteReader(connString, CommandType.StoredProcedure, "GetOrders");
  611.         /// </remarks>
  612.         /// <param name="connectionString">a valid connection string for a SqlConnection</param>
  613.         /// <param name="commandType">the CommandType (stored procedure, text, etc.)</param>
  614.         /// <param name="commandText">the stored procedure name or T-SQL command</param>
  615.         /// <returns>a SqlDataReader containing the resultset generated by the command</returns>
  616.         public static SqlDataReader ExecuteReader(string connectionString, CommandType commandType, string commandText)
  617.         {
  618.             //pass through the call providing null for the set of SqlParameters
  619.             return ExecuteReader(connectionString, commandType, commandText, (SqlParameter[])null);
  620.         }
  621.         /// <summary>
  622.         /// Execute a SqlCommand (that returns a resultset) against the database specified in the connection string 
  623.         /// using the provided parameters.
  624.         /// </summary>
  625.         /// <remarks>
  626.         /// e.g.:  
  627.         ///  SqlDataReader dr = ExecuteReader(connString, CommandType.StoredProcedure, "GetOrders", new SqlParameter("@prodid", 24));
  628.         /// </remarks>
  629.         /// <param name="connectionString">a valid connection string for a SqlConnection</param>
  630.         /// <param name="commandType">the CommandType (stored procedure, text, etc.)</param>
  631.         /// <param name="commandText">the stored procedure name or T-SQL command</param>
  632.         /// <param name="commandParameters">an array of SqlParamters used to execute the command</param>
  633.         /// <returns>a SqlDataReader containing the resultset generated by the command</returns>
  634.         public static SqlDataReader ExecuteReader(string connectionString, CommandType commandType, string commandText, params SqlParameter[] commandParameters)
  635.         {
  636.             //create & open a SqlConnection
  637.             SqlConnection cn = new SqlConnection(connectionString);
  638.             cn.Open();
  639.             try
  640.             {
  641.                 //call the private overload that takes an internally owned connection in place of the connection string
  642.                 return ExecuteReader(cn, null, commandType, commandText, commandParameters, SqlConnectionOwnership.Internal);
  643.             }
  644.             catch
  645.             {
  646.                 //if we fail to return the SqlDatReader, we need to close the connection ourselves
  647.                 cn.Close();
  648.                 throw;
  649.             }
  650.         }
  651.         /// <summary>
  652.         /// Execute a stored procedure via a SqlCommand (that returns a resultset) against the database specified in 
  653.         /// the connection string using the provided parameter values.  This method will query the database to discover the parameters for the 
  654.         /// stored procedure (the first time each stored procedure is called), and assign the values based on parameter order.
  655.         /// </summary>
  656.         /// <remarks>
  657.         /// This method provides no access to output parameters or the stored procedure's return value parameter.
  658.         /// 
  659.         /// e.g.:  
  660.         ///  SqlDataReader dr = ExecuteReader(connString, "GetOrders", 24, 36);
  661.         /// </remarks>
  662.         /// <param name="connectionString">a valid connection string for a SqlConnection</param>
  663.         /// <param name="spName">the name of the stored procedure</param>
  664.         /// <param name="parameterValues">an array of objects to be assigned as the input values of the stored procedure</param>
  665.         /// <returns>a SqlDataReader containing the resultset generated by the command</returns>
  666.         public static SqlDataReader ExecuteReader(string connectionString, string spName, params object[] parameterValues)
  667.         {
  668.             //if we receive parameter values, we need to figure out where they go
  669.             if ((parameterValues != null) && (parameterValues.Length > 0))
  670.             {
  671.                 //pull the parameters for this stored procedure from the parameter cache (or discover them & populate the cache)
  672.                 SqlParameter[] commandParameters = SqlHelperParameterCache.GetSpParameterSet(connectionString, spName);
  673.                 //assign the provided values to these parameters based on parameter order
  674.                 AssignParameterValues(commandParameters, parameterValues);
  675.                 //call the overload that takes an array of SqlParameters
  676.                 return ExecuteReader(connectionString, CommandType.StoredProcedure, spName, commandParameters);
  677.             }
  678.             //otherwise we can just call the SP without params
  679.             else
  680.             {
  681.                 return ExecuteReader(connectionString, CommandType.StoredProcedure, spName);
  682.             }
  683.         }
  684.         /// <summary>
  685.         /// Execute a SqlCommand (that returns a resultset and takes no parameters) against the provided SqlConnection. 
  686.         /// </summary>
  687.         /// <remarks>
  688.         /// e.g.:  
  689.         ///  SqlDataReader dr = ExecuteReader(conn, CommandType.StoredProcedure, "GetOrders");
  690.         /// </remarks>
  691.         /// <param name="connection">a valid SqlConnection</param>
  692.         /// <param name="commandType">the CommandType (stored procedure, text, etc.)</param>
  693.         /// <param name="commandText">the stored procedure name or T-SQL command</param>
  694.         /// <returns>a SqlDataReader containing the resultset generated by the command</returns>
  695.         public static SqlDataReader ExecuteReader(SqlConnection connection, CommandType commandType, string commandText)
  696.         {
  697.             //pass through the call providing null for the set of SqlParameters
  698.             return ExecuteReader(connection, commandType, commandText, (SqlParameter[])null);
  699.         }
  700.         /// <summary>
  701.         /// Execute a SqlCommand (that returns a resultset) against the specified SqlConnection 
  702.         /// using the provided parameters.
  703.         /// </summary>
  704.         /// <remarks>
  705.         /// e.g.:  
  706.         ///  SqlDataReader dr = ExecuteReader(conn, CommandType.StoredProcedure, "GetOrders", new SqlParameter("@prodid", 24));
  707.         /// </remarks>
  708.         /// <param name="connection">a valid SqlConnection</param>
  709.         /// <param name="commandType">the CommandType (stored procedure, text, etc.)</param>
  710.         /// <param name="commandText">the stored procedure name or T-SQL command</param>
  711.         /// <param name="commandParameters">an array of SqlParamters used to execute the command</param>
  712.         /// <returns>a SqlDataReader containing the resultset generated by the command</returns>
  713.         public static SqlDataReader ExecuteReader(SqlConnection connection, CommandType commandType, string commandText, params SqlParameter[] commandParameters)
  714.         {
  715.             //pass through the call to the private overload using a null transaction value and an externally owned connection
  716.             return ExecuteReader(connection, (SqlTransaction)null, commandType, commandText, commandParameters, SqlConnectionOwnership.External);
  717.         }
  718.         /// <summary>
  719.         /// Execute a stored procedure via a SqlCommand (that returns a resultset) against the specified SqlConnection 
  720.         /// using the provided parameter values.  This method will query the database to discover the parameters for the 
  721.         /// stored procedure (the first time each stored procedure is called), and assign the values based on parameter order.
  722.         /// </summary>
  723.         /// <remarks>
  724.         /// This method provides no access to output parameters or the stored procedure's return value parameter.
  725.         /// 
  726.         /// e.g.:  
  727.         ///  SqlDataReader dr = ExecuteReader(conn, "GetOrders", 24, 36);
  728.         /// </remarks>
  729.         /// <param name="connection">a valid SqlConnection</param>
  730.         /// <param name="spName">the name of the stored procedure</param>
  731.         /// <param name="parameterValues">an array of objects to be assigned as the input values of the stored procedure</param>
  732.         /// <returns>a SqlDataReader containing the resultset generated by the command</returns>
  733.         public static SqlDataReader ExecuteReader(SqlConnection connection, string spName, params object[] parameterValues)
  734.         {
  735.             //if we receive parameter values, we need to figure out where they go
  736.             if ((parameterValues != null) && (parameterValues.Length > 0))
  737.             {
  738.                 SqlParameter[] commandParameters = SqlHelperParameterCache.GetSpParameterSet(connection.ConnectionString, spName);
  739.                 AssignParameterValues(commandParameters, parameterValues);
  740.                 return ExecuteReader(connection, CommandType.StoredProcedure, spName, commandParameters);
  741.             }
  742.             //otherwise we can just call the SP without params
  743.             else
  744.             {
  745.                 return ExecuteReader(connection, CommandType.StoredProcedure, spName);
  746.             }
  747.         }
  748.         /// <summary>
  749.         /// Execute a SqlCommand (that returns a resultset and takes no parameters) against the provided SqlTransaction. 
  750.         /// </summary>
  751.         /// <remarks>
  752.         /// e.g.:  
  753.         ///  SqlDataReader dr = ExecuteReader(trans, CommandType.StoredProcedure, "GetOrders");
  754.         /// </remarks>
  755.         /// <param name="transaction">a valid SqlTransaction</param>
  756.         /// <param name="commandType">the CommandType (stored procedure, text, etc.)</param>
  757.         /// <param name="commandText">the stored procedure name or T-SQL command</param>
  758.         /// <returns>a SqlDataReader containing the resultset generated by the command</returns>
  759.         public static SqlDataReader ExecuteReader(SqlTransaction transaction, CommandType commandType, string commandText)
  760.         {
  761.             //pass through the call providing null for the set of SqlParameters
  762.             return ExecuteReader(transaction, commandType, commandText, (SqlParameter[])null);
  763.         }
  764.         /// <summary>
  765.         /// Execute a SqlCommand (that returns a resultset) against the specified SqlTransaction
  766.         /// using the provided parameters.
  767.         /// </summary>
  768.         /// <remarks>
  769.         /// e.g.:  
  770.         ///   SqlDataReader dr = ExecuteReader(trans, CommandType.StoredProcedure, "GetOrders", new SqlParameter("@prodid", 24));
  771.         /// </remarks>
  772.         /// <param name="transaction">a valid SqlTransaction</param>
  773.         /// <param name="commandType">the CommandType (stored procedure, text, etc.)</param>
  774.         /// <param name="commandText">the stored procedure name or T-SQL command</param>
  775.         /// <param name="commandParameters">an array of SqlParamters used to execute the command</param>
  776.         /// <returns>a SqlDataReader containing the resultset generated by the command</returns>
  777.         public static SqlDataReader ExecuteReader(SqlTransaction transaction, CommandType commandType, string commandText, params SqlParameter[] commandParameters)
  778.         {
  779.             //pass through to private overload, indicating that the connection is owned by the caller
  780.             return ExecuteReader(transaction.Connection, transaction, commandType, commandText, commandParameters, SqlConnectionOwnership.External);
  781.         }
  782.         /// <summary>
  783.         /// Execute a stored procedure via a SqlCommand (that returns a resultset) against the specified
  784.         /// SqlTransaction using the provided parameter values.  This method will query the database to discover the parameters for the 
  785.         /// stored procedure (the first time each stored procedure is called), and assign the values based on parameter order.
  786.         /// </summary>
  787.         /// <remarks>
  788.         /// This method provides no access to output parameters or the stored procedure's return value parameter.
  789.         /// 
  790.         /// e.g.:  
  791.         ///  SqlDataReader dr = ExecuteReader(trans, "GetOrders", 24, 36);
  792.         /// </remarks>
  793.         /// <param name="transaction">a valid SqlTransaction</param>
  794.         /// <param name="spName">the name of the stored procedure</param>
  795.         /// <param name="parameterValues">an array of objects to be assigned as the input values of the stored procedure</param>
  796.         /// <returns>a SqlDataReader containing the resultset generated by the command</returns>
  797.         public static SqlDataReader ExecuteReader(SqlTransaction transaction, string spName, params object[] parameterValues)
  798.         {
  799.             //if we receive parameter values, we need to figure out where they go
  800.             if ((parameterValues != null) && (parameterValues.Length > 0))
  801.             {
  802.                 SqlParameter[] commandParameters = SqlHelperParameterCache.GetSpParameterSet(transaction.Connection.ConnectionString, spName);
  803.                 AssignParameterValues(commandParameters, parameterValues);
  804.                 return ExecuteReader(transaction, CommandType.StoredProcedure, spName, commandParameters);
  805.             }
  806.             //otherwise we can just call the SP without params
  807.             else
  808.             {
  809.                 return ExecuteReader(transaction, CommandType.StoredProcedure, spName);
  810.             }
  811.         }
  812.         #endregion ExecuteReader
  813.         #region ExecuteScalar
  814.         /// <summary>
  815.         /// Execute a SqlCommand (that returns a 1x1 resultset and takes no parameters) against the database specified in 
  816.         /// the connection string. 
  817.         /// </summary>
  818.         /// <remarks>
  819.         /// e.g.:  
  820.         ///  int orderCount = (int)ExecuteScalar(connString, CommandType.StoredProcedure, "GetOrderCount");
  821.         /// </remarks>
  822.         /// <param name="connectionString">a valid connection string for a SqlConnection</param>
  823.         /// <param name="commandType">the CommandType (stored procedure, text, etc.)</param>
  824.         /// <param name="commandText">the stored procedure name or T-SQL command</param>
  825.         /// <returns>an object containing the value in the 1x1 resultset generated by the command</returns>
  826.         public static object ExecuteScalar(string connectionString, CommandType commandType, string commandText)
  827.         {
  828.             //pass through the call providing null for the set of SqlParameters
  829.             return ExecuteScalar(connectionString, commandType, commandText, (SqlParameter[])null);
  830.         }
  831.         /// <summary>
  832.         /// Execute a SqlCommand (that returns a 1x1 resultset) against the database specified in the connection string 
  833.         /// using the provided parameters.
  834.         /// </summary>
  835.         /// <remarks>
  836.         /// e.g.:  
  837.         ///  int orderCount = (int)ExecuteScalar(connString, CommandType.StoredProcedure, "GetOrderCount", 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>an object containing the value in the 1x1 resultset generated by the command</returns>
  844.         public static object ExecuteScalar(string connectionString, CommandType commandType, string commandText, params SqlParameter[] commandParameters)
  845.         {
  846.             //create & open a SqlConnection, and dispose of it after we are done.
  847.             using (SqlConnection cn = new SqlConnection(connectionString))
  848.             {
  849.                 cn.Open();
  850.                 //call the overload that takes a connection in place of the connection string
  851.                 return ExecuteScalar(cn, commandType, commandText, commandParameters);
  852.             }
  853.         }
  854.         /// <summary>
  855.         /// Execute a stored procedure via a SqlCommand (that returns a 1x1 resultset) against the database specified in 
  856.         /// the connection string using the provided parameter values.  This method will query the database to discover the parameters for the 
  857.         /// stored procedure (the first time each stored procedure is called), and assign the values based on parameter order.
  858.         /// </summary>
  859.         /// <remarks>
  860.         /// This method provides no access to output parameters or the stored procedure's return value parameter.
  861.         /// 
  862.         /// e.g.:  
  863.         ///  int orderCount = (int)ExecuteScalar(connString, "GetOrderCount", 24, 36);
  864.         /// </remarks>
  865.         /// <param name="connectionString">a valid connection string for a SqlConnection</param>
  866.         /// <param name="spName">the name of the stored procedure</param>
  867.         /// <param name="parameterValues">an array of objects to be assigned as the input values of the stored procedure</param>
  868.         /// <returns>an object containing the value in the 1x1 resultset generated by the command</returns>
  869.         public static object ExecuteScalar(string connectionString, string spName, params object[] parameterValues)
  870.         {
  871.             //if we receive parameter values, we need to figure out where they go
  872.             if ((parameterValues != null) && (parameterValues.Length > 0))
  873.             {
  874.                 //pull the parameters for this stored procedure from the parameter cache (or discover them & populate the cache)
  875.                 SqlParameter[] commandParameters = SqlHelperParameterCache.GetSpParameterSet(connectionString, spName);
  876.                 //assign the provided values to these parameters based on parameter order
  877.                 AssignParameterValues(commandParameters, parameterValues);
  878.                 //call the overload that takes an array of SqlParameters
  879.                 return ExecuteScalar(connectionString, CommandType.StoredProcedure, spName, commandParameters);
  880.             }
  881.             //otherwise we can just call the SP without params
  882.             else
  883.             {
  884.                 return ExecuteScalar(connectionString, CommandType.StoredProcedure, spName);
  885.             }
  886.         }
  887.         /// <summary>
  888.         /// Execute a SqlCommand (that returns a 1x1 resultset and takes no parameters) against the provided SqlConnection. 
  889.         /// </summary>
  890.         /// <remarks>
  891.         /// e.g.:  
  892.         ///  int orderCount = (int)ExecuteScalar(conn, CommandType.StoredProcedure, "GetOrderCount");
  893.         /// </remarks>
  894.         /// <param name="connection">a valid SqlConnection</param>
  895.         /// <param name="commandType">the CommandType (stored procedure, text, etc.)</param>
  896.         /// <param name="commandText">the stored procedure name or T-SQL command</param>
  897.         /// <returns>an object containing the value in the 1x1 resultset generated by the command</returns>
  898.         public static object ExecuteScalar(SqlConnection connection, CommandType commandType, string commandText)
  899.         {
  900.             //pass through the call providing null for the set of SqlParameters
  901.             return ExecuteScalar(connection, commandType, commandText, (SqlParameter[])null);
  902.         }
  903.         /// <summary>
  904.         /// Execute a SqlCommand (that returns a 1x1 resultset) against the specified SqlConnection 
  905.         /// using the provided parameters.
  906.         /// </summary>
  907.         /// <remarks>
  908.         /// e.g.:  
  909.         ///  int orderCount = (int)ExecuteScalar(conn, CommandType.StoredProcedure, "GetOrderCount", new SqlParameter("@prodid", 24));
  910.         /// </remarks>
  911.         /// <param name="connection">a valid SqlConnection</param>
  912.         /// <param name="commandType">the CommandType (stored procedure, text, etc.)</param>
  913.         /// <param name="commandText">the stored procedure name or T-SQL command</param>
  914.         /// <param name="commandParameters">an array of SqlParamters used to execute the command</param>
  915.         /// <returns>an object containing the value in the 1x1 resultset generated by the command</returns>
  916.         public static object ExecuteScalar(SqlConnection connection, CommandType commandType, string commandText, params SqlParameter[] commandParameters)
  917.         {
  918.             //create a command and prepare it for execution
  919.             SqlCommand cmd = new SqlCommand();
  920.             PrepareCommand(cmd, connection, (SqlTransaction)null, commandType, commandText, commandParameters);
  921.             //execute the command & return the results
  922.             object retval = cmd.ExecuteScalar();
  923.             // detach the SqlParameters from the command object, so they can be used again.
  924.             cmd.Parameters.Clear();
  925.             return retval;
  926.         }
  927.         /// <summary>
  928.         /// Execute a stored procedure via a SqlCommand (that returns a 1x1 resultset) against the specified SqlConnection 
  929.         /// using the provided parameter values.  This method will query the database to discover the parameters for the 
  930.         /// stored procedure (the first time each stored procedure is called), and assign the values based on parameter order.
  931.         /// </summary>
  932.         /// <remarks>
  933.         /// This method provides no access to output parameters or the stored procedure's return value parameter.
  934.         /// 
  935.         /// e.g.:  
  936.         ///  int orderCount = (int)ExecuteScalar(conn, "GetOrderCount", 24, 36);
  937.         /// </remarks>
  938.         /// <param name="connection">a valid SqlConnection</param>
  939.         /// <param name="spName">the name of the stored procedure</param>
  940.         /// <param name="parameterValues">an array of objects to be assigned as the input values of the stored procedure</param>
  941.         /// <returns>an object containing the value in the 1x1 resultset generated by the command</returns>
  942.         public static object ExecuteScalar(SqlConnection connection, string spName, params object[] parameterValues)
  943.         {
  944.             //if we receive parameter values, we need to figure out where they go
  945.             if ((parameterValues != null) && (parameterValues.Length > 0))
  946.             {
  947.                 //pull the parameters for this stored procedure from the parameter cache (or discover them & populate the cache)
  948.                 SqlParameter[] commandParameters = SqlHelperParameterCache.GetSpParameterSet(connection.ConnectionString, spName);
  949.                 //assign the provided values to these parameters based on parameter order
  950.                 AssignParameterValues(commandParameters, parameterValues);
  951.                 //call the overload that takes an array of SqlParameters
  952.                 return ExecuteScalar(connection, CommandType.StoredProcedure, spName, commandParameters);
  953.             }
  954.             //otherwise we can just call the SP without params
  955.             else
  956.             {
  957.                 return ExecuteScalar(connection, CommandType.StoredProcedure, spName);
  958.             }
  959.         }
  960.         /// <summary>
  961.         /// Execute a SqlCommand (that returns a 1x1 resultset and takes no parameters) against the provided SqlTransaction. 
  962.         /// </summary>
  963.         /// <remarks>
  964.         /// e.g.:  
  965.         ///  int orderCount = (int)ExecuteScalar(trans, CommandType.StoredProcedure, "GetOrderCount");
  966.         /// </remarks>
  967.         /// <param name="transaction">a valid SqlTransaction</param>
  968.         /// <param name="commandType">the CommandType (stored procedure, text, etc.)</param>
  969.         /// <param name="commandText">the stored procedure name or T-SQL command</param>
  970.         /// <returns>an object containing the value in the 1x1 resultset generated by the command</returns>
  971.         public static object ExecuteScalar(SqlTransaction transaction, CommandType commandType, string commandText)
  972.         {
  973.             //pass through the call providing null for the set of SqlParameters
  974.             return ExecuteScalar(transaction, commandType, commandText, (SqlParameter[])null);
  975.         }
  976.         /// <summary>
  977.         /// Execute a SqlCommand (that returns a 1x1 resultset) against the specified SqlTransaction
  978.         /// using the provided parameters.
  979.         /// </summary>
  980.         /// <remarks>
  981.         /// e.g.:  
  982.         ///  int orderCount = (int)ExecuteScalar(trans, CommandType.StoredProcedure, "GetOrderCount", new SqlParameter("@prodid", 24));
  983.         /// </remarks>
  984.         /// <param name="transaction">a valid SqlTransaction</param>
  985.         /// <param name="commandType">the CommandType (stored procedure, text, etc.)</param>
  986.         /// <param name="commandText">the stored procedure name or T-SQL command</param>
  987.         /// <param name="commandParameters">an array of SqlParamters used to execute the command</param>
  988.         /// <returns>an object containing the value in the 1x1 resultset generated by the command</returns>
  989.         public static object ExecuteScalar(SqlTransaction transaction, CommandType commandType, string commandText, params SqlParameter[] commandParameters)
  990.         {
  991.             //create a command and prepare it for execution
  992.             SqlCommand cmd = new SqlCommand();
  993.             PrepareCommand(cmd, transaction.Connection, transaction, commandType, commandText, commandParameters);
  994.             //execute the command & return the results
  995.             object retval = cmd.ExecuteScalar();
  996.             // detach the SqlParameters from the command object, so they can be used again.
  997.             cmd.Parameters.Clear();
  998.             return retval;
  999.         }
  1000.         /// <summary>
  1001.         /// Execute a stored procedure via a SqlCommand (that returns a 1x1 resultset) against the specified
  1002.         /// SqlTransaction using the provided parameter values.  This method will query the database to discover the parameters for the 
  1003.         /// stored procedure (the first time each stored procedure is called), and assign the values based on parameter order.
  1004.         /// </summary>
  1005.         /// <remarks>
  1006.         /// This method provides no access to output parameters or the stored procedure's return value parameter.
  1007.         /// 
  1008.         /// e.g.:  
  1009.         ///  int orderCount = (int)ExecuteScalar(trans, "GetOrderCount", 24, 36);
  1010.         /// </remarks>
  1011.         /// <param name="transaction">a valid SqlTransaction</param>
  1012.         /// <param name="spName">the name of the stored procedure</param>
  1013.         /// <param name="parameterValues">an array of objects to be assigned as the input values of the stored procedure</param>
  1014.         /// <returns>an object containing the value in the 1x1 resultset generated by the command</returns>
  1015.         public static object ExecuteScalar(SqlTransaction transaction, string spName, params object[] parameterValues)
  1016.         {
  1017.             //if we receive parameter values, we need to figure out where they go
  1018.             if ((parameterValues != null) && (parameterValues.Length > 0))
  1019.             {
  1020.                 //pull the parameters for this stored procedure from the parameter cache (or discover them & populate the cache)
  1021.                 SqlParameter[] commandParameters = SqlHelperParameterCache.GetSpParameterSet(transaction.Connection.ConnectionString, spName);
  1022.                 //assign the provided values to these parameters based on parameter order
  1023.                 AssignParameterValues(commandParameters, parameterValues);
  1024.                 //call the overload that takes an array of SqlParameters
  1025.                 return ExecuteScalar(transaction, CommandType.StoredProcedure, spName, commandParameters);
  1026.             }
  1027.             //otherwise we can just call the SP without params
  1028.             else
  1029.             {
  1030.                 return ExecuteScalar(transaction, CommandType.StoredProcedure, spName);
  1031.             }
  1032.         }
  1033.         #endregion ExecuteScalar
  1034.         #region ExecuteXmlReader
  1035.         /// <summary>
  1036.         /// Execute a SqlCommand (that returns a resultset and takes no parameters) against the provided SqlConnection. 
  1037.         /// </summary>
  1038.         /// <remarks>
  1039.         /// e.g.:  
  1040.         ///  XmlReader r = ExecuteXmlReader(conn, CommandType.StoredProcedure, "GetOrders");
  1041.         /// </remarks>
  1042.         /// <param name="connection">a valid SqlConnection</param>
  1043.         /// <param name="commandType">the CommandType (stored procedure, text, etc.)</param>
  1044.         /// <param name="commandText">the stored procedure name or T-SQL command using "FOR XML AUTO"</param>
  1045.         /// <returns>an XmlReader containing the resultset generated by the command</returns>
  1046.         public static XmlReader ExecuteXmlReader(SqlConnection connection, CommandType commandType, string commandText)
  1047.         {
  1048.             //pass through the call providing null for the set of SqlParameters
  1049.             return ExecuteXmlReader(connection, commandType, commandText, (SqlParameter[])null);
  1050.         }
  1051.         /// <summary>
  1052.         /// Execute a SqlCommand (that returns a resultset) against the specified SqlConnection 
  1053.         /// using the provided parameters.
  1054.         /// </summary>
  1055.         /// <remarks>
  1056.         /// e.g.:  
  1057.         ///  XmlReader r = ExecuteXmlReader(conn, CommandType.StoredProcedure, "GetOrders", new SqlParameter("@prodid", 24));
  1058.         /// </remarks>
  1059.         /// <param name="connection">a valid SqlConnection</param>
  1060.         /// <param name="commandType">the CommandType (stored procedure, text, etc.)</param>
  1061.         /// <param name="commandText">the stored procedure name or T-SQL command using "FOR XML AUTO"</param>
  1062.         /// <param name="commandParameters">an array of SqlParamters used to execute the command</param>
  1063.         /// <returns>an XmlReader containing the resultset generated by the command</returns>
  1064.         public static XmlReader ExecuteXmlReader(SqlConnection connection, CommandType commandType, string commandText, params SqlParameter[] commandParameters)
  1065.         {
  1066.             //create a command and prepare it for execution
  1067.             SqlCommand cmd = new SqlCommand();
  1068.             PrepareCommand(cmd, connection, (SqlTransaction)null, commandType, commandText, commandParameters);
  1069.             //create the DataAdapter & DataSet
  1070.             XmlReader retval = cmd.ExecuteXmlReader();
  1071.             // detach the SqlParameters from the command object, so they can be used again.
  1072.             cmd.Parameters.Clear();
  1073.             return retval;
  1074.         }
  1075.         /// <summary>
  1076.         /// Execute a stored procedure via a SqlCommand (that returns a resultset) against the specified SqlConnection 
  1077.         /// using the provided parameter values.  This method will query the database to discover the parameters for the 
  1078.         /// stored procedure (the first time each stored procedure is called), and assign the values based on parameter order.
  1079.         /// </summary>
  1080.         /// <remarks>
  1081.         /// This method provides no access to output parameters or the stored procedure's return value parameter.
  1082.         /// 
  1083.         /// e.g.:  
  1084.         ///  XmlReader r = ExecuteXmlReader(conn, "GetOrders", 24, 36);
  1085.         /// </remarks>
  1086.         /// <param name="connection">a valid SqlConnection</param>
  1087.         /// <param name="spName">the name of the stored procedure using "FOR XML AUTO"</param>
  1088.         /// <param name="parameterValues">an array of objects to be assigned as the input values of the stored procedure</param>
  1089.         /// <returns>an XmlReader containing the resultset generated by the command</returns>
  1090.         public static XmlReader ExecuteXmlReader(SqlConnection connection, string spName, params object[] parameterValues)
  1091.         {
  1092.             //if we receive parameter values, we need to figure out where they go
  1093.             if ((parameterValues != null) && (parameterValues.Length > 0))
  1094.             {
  1095.                 //pull the parameters for this stored procedure from the parameter cache (or discover them & populate the cache)
  1096.                 SqlParameter[] commandParameters = SqlHelperParameterCache.GetSpParameterSet(connection.ConnectionString, spName);
  1097.                 //assign the provided values to these parameters based on parameter order
  1098.                 AssignParameterValues(commandParameters, parameterValues);
  1099.                 //call the overload that takes an array of SqlParameters
  1100.                 return ExecuteXmlReader(connection, CommandType.StoredProcedure, spName, commandParameters);
  1101.             }
  1102.             //otherwise we can just call the SP without params
  1103.             else
  1104.             {
  1105.                 return ExecuteXmlReader(connection, CommandType.StoredProcedure, spName);
  1106.             }
  1107.         }
  1108.         /// <summary>
  1109.         /// Execute a SqlCommand (that returns a resultset and takes no parameters) against the provided SqlTransaction. 
  1110.         /// </summary>
  1111.         /// <remarks>
  1112.         /// e.g.:  
  1113.         ///  XmlReader r = ExecuteXmlReader(trans, CommandType.StoredProcedure, "GetOrders");
  1114.         /// </remarks>
  1115.         /// <param name="transaction">a valid SqlTransaction</param>
  1116.         /// <param name="commandType">the CommandType (stored procedure, text, etc.)</param>
  1117.         /// <param name="commandText">the stored procedure name or T-SQL command using "FOR XML AUTO"</param>
  1118.         /// <returns>an XmlReader containing the resultset generated by the command</returns>
  1119.         public static XmlReader ExecuteXmlReader(SqlTransaction transaction, CommandType commandType, string commandText)
  1120.         {
  1121.             //pass through the call providing null for the set of SqlParameters
  1122.             return ExecuteXmlReader(transaction, commandType, commandText, (SqlParameter[])null);
  1123.         }
  1124.         /// <summary>
  1125.         /// Execute a SqlCommand (that returns a resultset) against the specified SqlTransaction
  1126.         /// using the provided parameters.
  1127.         /// </summary>
  1128.         /// <remarks>
  1129.         /// e.g.:  
  1130.         ///  XmlReader r = ExecuteXmlReader(trans, CommandType.StoredProcedure, "GetOrders", new SqlParameter("@prodid", 24));
  1131.         /// </remarks>
  1132.         /// <param name="transaction">a valid SqlTransaction</param>
  1133.         /// <param name="commandType">the CommandType (stored procedure, text, etc.)</param>
  1134.         /// <param name="commandText">the stored procedure name or T-SQL command using "FOR XML AUTO"</param>
  1135.         /// <param name="commandParameters">an array of SqlParamters used to execute the command</param>
  1136.         /// <returns>an XmlReader containing the resultset generated by the command</returns>
  1137.         public static XmlReader ExecuteXmlReader(SqlTransaction transaction, CommandType commandType, string commandText, params SqlParameter[] commandParameters)
  1138.         {
  1139.             //create a command and prepare it for execution
  1140.             SqlCommand cmd = new SqlCommand();
  1141.             PrepareCommand(cmd, transaction.Connection, transaction, commandType, commandText, commandParameters);
  1142.             //create the DataAdapter & DataSet
  1143.             XmlReader retval = cmd.ExecuteXmlReader();
  1144.             // detach the SqlParameters from the command object, so they can be used again.
  1145.             cmd.Parameters.Clear();
  1146.             return retval;
  1147.         }
  1148.         /// <summary>
  1149.         /// Execute a stored procedure via a SqlCommand (that returns a resultset) against the specified 
  1150.         /// SqlTransaction using the provided parameter values.  This method will query the database to discover the parameters for the 
  1151.         /// stored procedure (the first time each stored procedure is called), and assign the values based on parameter order.
  1152.         /// </summary>
  1153.         /// <remarks>
  1154.         /// This method provides no access to output parameters or the stored procedure's return value parameter.
  1155.         /// 
  1156.         /// e.g.:  
  1157.         ///  XmlReader r = ExecuteXmlReader(trans, "GetOrders", 24, 36);
  1158.         /// </remarks>
  1159.         /// <param name="transaction">a valid SqlTransaction</param>
  1160.         /// <param name="spName">the name of the stored procedure</param>
  1161.         /// <param name="parameterValues">an array of objects to be assigned as the input values of the stored procedure</param>
  1162.         /// <returns>a dataset containing the resultset generated by the command</returns>
  1163.         public static XmlReader ExecuteXmlReader(SqlTransaction transaction, string spName, params object[] parameterValues)
  1164.         {
  1165.             //if we receive parameter values, we need to figure out where they go
  1166.             if ((parameterValues != null) && (parameterValues.Length > 0))
  1167.             {
  1168.                 //pull the parameters for this stored procedure from the parameter cache (or discover them & populate the cache)
  1169.                 SqlParameter[] commandParameters = SqlHelperParameterCache.GetSpParameterSet(transaction.Connection.ConnectionString, spName);
  1170.                 //assign the provided values to these parameters based on parameter order
  1171.                 AssignParameterValues(commandParameters, parameterValues);
  1172.                 //call the overload that takes an array of SqlParameters
  1173.                 return ExecuteXmlReader(transaction, CommandType.StoredProcedure, spName, commandParameters);
  1174.             }
  1175.             //otherwise we can just call the SP without params
  1176.             else
  1177.             {
  1178.                 return ExecuteXmlReader(transaction, CommandType.StoredProcedure, spName);
  1179.             }
  1180.         }
  1181.         #endregion ExecuteXmlReader
  1182.     }
  1183.     /// <summary>
  1184.     /// SqlHelperParameterCache provides functions to leverage a static cache of procedure parameters, and the
  1185.     /// ability to discover parameters for stored procedures at run-time.
  1186.     /// </summary>
  1187.     public sealed class SqlHelperParameterCache
  1188.     {
  1189.         #region private methods, variables, and constructors
  1190.         //Since this class provides only static methods, make the default constructor private to prevent 
  1191.         //instances from being created with "new SqlHelperParameterCache()".
  1192.         private SqlHelperParameterCache() { }
  1193.         private static Hashtable paramCache = Hashtable.Synchronized(new Hashtable());
  1194.         /// <summary>
  1195.         /// resolve at run time the appropriate set of SqlParameters for a stored procedure
  1196.         /// </summary>
  1197.         /// <param name="connectionString">a valid connection string for a SqlConnection</param>
  1198.         /// <param name="spName">the name of the stored procedure</param>
  1199.         /// <param name="includeReturnValueParameter">whether or not to include their return value parameter</param>
  1200.         /// <returns></returns>
  1201.         private static SqlParameter[] DiscoverSpParameterSet(string connectionString, string spName, bool includeReturnValueParameter)
  1202.         {
  1203.             using (SqlConnection cn = new SqlConnection(connectionString))
  1204.             using (SqlCommand cmd = new SqlCommand(spName, cn))
  1205.             {
  1206.                 cn.Open();
  1207.                 cmd.CommandType = CommandType.StoredProcedure;
  1208.                 SqlCommandBuilder.DeriveParameters(cmd);
  1209.                 if (!includeReturnValueParameter)
  1210.                 {
  1211.                     cmd.Parameters.RemoveAt(0);
  1212.                 }
  1213.                 SqlParameter[] discoveredParameters = new SqlParameter[cmd.Parameters.Count]; ;
  1214.                 cmd.Parameters.CopyTo(discoveredParameters, 0);
  1215.                 return discoveredParameters;
  1216.             }
  1217.         }
  1218.         //deep copy of cached SqlParameter array
  1219.         private static SqlParameter[] CloneParameters(SqlParameter[] originalParameters)
  1220.         {
  1221.             SqlParameter[] clonedParameters = new SqlParameter[originalParameters.Length];
  1222.             for (int i = 0, j = originalParameters.Length; i < j; i++)
  1223.             {
  1224.                 clonedParameters[i] = (SqlParameter)((ICloneable)originalParameters[i]).Clone();
  1225.             }
  1226.             return clonedParameters;
  1227.         }
  1228.         #endregion private methods, variables, and constructors
  1229.         #region caching functions
  1230.         /// <summary>
  1231.         /// add parameter array to the cache
  1232.         /// </summary>
  1233.         /// <param name="connectionString">a valid connection string for a SqlConnection</param>
  1234.         /// <param name="commandText">the stored procedure name or T-SQL command</param>
  1235.         /// <param name="commandParameters">an array of SqlParamters to be cached</param>
  1236.         public static void CacheParameterSet(string connectionString, string commandText, params SqlParameter[] commandParameters)
  1237.         {
  1238.             string hashKey = connectionString + ":" + commandText;
  1239.             paramCache[hashKey] = commandParameters;
  1240.         }
  1241.         /// <summary>
  1242.         /// retrieve a parameter array from the cache
  1243.         /// </summary>
  1244.         /// <param name="connectionString">a valid connection string for a SqlConnection</param>
  1245.         /// <param name="commandText">the stored procedure name or T-SQL command</param>
  1246.         /// <returns>an array of SqlParamters</returns>
  1247.         public static SqlParameter[] GetCachedParameterSet(string connectionString, string commandText)
  1248.         {
  1249.             string hashKey = connectionString + ":" + commandText;
  1250.             SqlParameter[] cachedParameters = (SqlParameter[])paramCache[hashKey];
  1251.             if (cachedParameters == null)
  1252.             {
  1253.                 return null;
  1254.             }
  1255.             else
  1256.             {
  1257.                 return CloneParameters(cachedParameters);
  1258.             }
  1259.         }
  1260.         #endregion caching functions
  1261.         #region Parameter Discovery Functions
  1262.         /// <summary>
  1263.         /// Retrieves the set of SqlParameters appropriate for the stored procedure
  1264.         /// </summary>
  1265.         /// <remarks>
  1266.         /// This method will query the database for this information, and then store it in a cache for future requests.
  1267.         /// </remarks>
  1268.         /// <param name="connectionString">a valid connection string for a SqlConnection</param>
  1269.         /// <param name="spName">the name of the stored procedure</param>
  1270.         /// <returns>an array of SqlParameters</returns>
  1271.         public static SqlParameter[] GetSpParameterSet(string connectionString, string spName)
  1272.         {
  1273.             return GetSpParameterSet(connectionString, spName, false);
  1274.         }
  1275.         /// <summary>
  1276.         /// Retrieves the set of SqlParameters appropriate for the stored procedure
  1277.         /// </summary>
  1278.         /// <remarks>
  1279.         /// This method will query the database for this information, and then store it in a cache for future requests.
  1280.         /// </remarks>
  1281.         /// <param name="connectionString">a valid connection string for a SqlConnection</param>
  1282.         /// <param name="spName">the name of the stored procedure</param>
  1283.         /// <param name="includeReturnValueParameter">a bool value indicating whether the return value parameter should be included in the results</param>
  1284.         /// <returns>an array of SqlParameters</returns>
  1285.         public static SqlParameter[] GetSpParameterSet(string connectionString, string spName, bool includeReturnValueParameter)
  1286.         {
  1287.             string hashKey = connectionString + ":" + spName + (includeReturnValueParameter ? ":include ReturnValue Parameter" : "");
  1288.             SqlParameter[] cachedParameters;
  1289.             cachedParameters = (SqlParameter[])paramCache[hashKey];
  1290.             if (cachedParameters == null)
  1291.             {
  1292.                 cachedParameters = (SqlParameter[])(paramCache[hashKey] = DiscoverSpParameterSet(connectionString, spName, includeReturnValueParameter));
  1293.             }
  1294.             return CloneParameters(cachedParameters);
  1295.         }
  1296.         #endregion Parameter Discovery Functions
  1297.     }
  1298. }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值