在数据驱动的应用程序中,存储过程具有许多优势。利用存储过程,数据库操作可以封装在单个命令中,为获取最佳性能而进行优化并通过附加的安全性得到增强。尽管通过以 SQL 语句的形式传递存储过程名称后接参数自变量即可调用存储过程,但如果使用 ADO.NET DbCommand 对象的 Parameters 集合,则可以更加显式地定义存储过程参数并访问输出参数和返回值。
若要调用存储过程,请将 Command 对象的 CommandType 设置为 StoredProcedure。CommandType 一旦设置为 StoredProcedure,就可以使用 Parameters 集合来定义参数,如以下示例所示。
注意
OdbcCommand 要求您在调用存储过程时提供完整的 ODBC CALL 语法。
- // Assumes that connection is a valid SqlConnection object.
- SqlCommand salesCommand = new SqlCommand("SalesByCategory",
- connection);
- salesCommand.CommandType = CommandType.StoredProcedure;
- SqlParameter parameter = salesCommand.Parameters.Add(
- "@CategoryName", SqlDbType.NVarChar, 15);
- parameter.Value = "Beverages";
- connection.Open();
- SqlDataReader reader = salesCommand.ExecuteReader();
- Console.WriteLine(
- "{0}, {1}", reader.GetName(0), reader.GetName(1));
- while (reader.Read())
- {
- Console.WriteLine("{0}, ${1}", reader.GetString(0),
- reader.GetDecimal(1));
- }
- reader.Close();
- connection.Close();
Parameter 对象可以使用 Parameter 构造函数来创建,或通过调用 Command 的 Parameters 集合的 Add 方法来创建。Parameters.Add 会将构造函数参数或现有 Parameter 对象用作输入。在将 Parameter 的 Value 设置为空引用时,请使用 DBNull.Value。
对于 Input 参数之外的参数,必须设置 ParameterDirection 属性来指定参数类型是 InputOutput、Output 还是 ReturnValue。以下示例演示为各种提供程序创建 Input、Output 和 ReturnValue 参数之间的差异。
SqlClient 示例
- // Assumes that connection is a valid SqlConnection object.
- SqlCommand command = new SqlCommand("SampleProc", connection);
- command.CommandType = CommandType.StoredProcedure;
- SqlParameter parameter = command.Parameters.Add(
- "RETURN_VALUE", SqlDbType.Int);
- parameter.Direction = ParameterDirection.ReturnValue;
- parameter = command.Parameters.Add(
- "@InputParm", SqlDbType.NVarChar, 12);
- parameter.Value = "Sample Value";
- parameter = command.Parameters.Add(
- "@OutputParm", SqlDbType.NVarChar, 28);
- parameter.Direction = ParameterDirection.Output;
- connection.Open();
- SqlDataReader reader = command.ExecuteReader();
- Console.WriteLine(
- "{0}, {1}", reader.GetName(0), reader.GetName(1));
- while (reader.Read())
- {
- Console.WriteLine(
- "{0}, {1}", reader.GetInt32(0), reader.GetString(1));
- }
- reader.Close();
- connection.Close();
- Console.WriteLine(" @OutputParm: {0}", command.Parameters["@OutputParm"].Value);
- Console.WriteLine("RETURN_VALUE: {0}", command.Parameters["RETURN_VALUE"].Value);
OleDb 示例
- OleDbCommand command = new OleDbCommand("SampleProc", connection);
- command.CommandType = CommandType.StoredProcedure;
- OleDbParameter parameter = command.Parameters.Add(
- "RETURN_VALUE", OleDbType.Integer);
- parameter.Direction = ParameterDirection.ReturnValue;
- parameter = command.Parameters.Add(
- "@InputParm", OleDbType.VarChar, 12);
- parameter.Value = "Sample Value";
- parameter = command.Parameters.Add(
- "@OutputParm", OleDbType.VarChar, 28);
- parameter.Direction = ParameterDirection.Output;
- connection.Open();
- OleDbDataReader reader = command.ExecuteReader();
- Console.WriteLine("{0}, {1}", reader.GetName(0), reader.GetName(1));
- while (reader.Read())
- {
- Console.WriteLine("{0}, {1}", reader.GetInt32(0), reader.GetString(1));
- }
- reader.Close();
- connection.Close();
- Console.WriteLine(" @OutputParm: {0}", command.Parameters["@OutputParm"].Value);
- Console.WriteLine("RETURN_VALUE: {0}", command.Parameters["RETURN_VALUE"].Value);
Odbc 示例
- OdbcCommand command = new OdbcCommand( _
- "{ ? = CALL SampleProc(?, ?) }", connection);
- command.CommandType = CommandType.StoredProcedure;
- OdbcParameter parameter = command.Parameters.Add( _
- "RETURN_VALUE", OdbcType.Int);
- parameter.Direction = ParameterDirection.ReturnValue;
- parameter = command.Parameters.Add( _
- "@InputParm", OdbcType.VarChar, 12);
- parameter.Value = "Sample Value";
- parameter = command.Parameters.Add( _
- "@OutputParm", OdbcType.VarChar, 28);
- parameter.Direction = ParameterDirection.Output;
- connection.Open();
- OdbcDataReader reader = command.ExecuteReader();
- Console.WriteLine("{0}, {1}", reader.GetName(0), reader.GetName(1));
- while (reader.Read())
- {
- Console.WriteLine( _
- "{0}, {1}", reader.GetInt32(0), reader.GetString(1));
- }
- reader.Close();
- connection.Close();
- Console.WriteLine(" @OutputParm: {0}", command.Parameters["@OutputParm"].Value);
- Console.WriteLine("RETURN_VALUE: {0}", command.Parameters["RETURN_VALUE"].Value);
对 SqlCommand 使用参数
在对 SqlCommand 使用参数时,添加到 Parameters 集合的参数的名称必须与存储过程中参数标记的名称相匹配。SQL Server .NET Framework 数据提供程序将存储过程中的参数视为命名参数并搜索匹配的参数标记。
SQL Server .NET Framework 数据提供程序不支持在向 SQL 语句或存储过程传递参数时使用问号 (?) 占位符。在这种情况下,必须使用命名参数,如以下示例所示,其中 @CustomerID 是命名参数。
SELECT * FROM Customers WHERE CustomerID = @CustomerID |
对 OleDbCommand 或 OdbcCommand 使用参数
在对 OleDbCommand 或 OdbcCommand 使用参数时,向 Parameters 集合中添加参数的顺序必须与存储过程中所定义的参数顺序相匹配。OLE DB .NET Framework 数据提供程序和 ODBC .NET Framework 数据提供程序将存储过程中的参数视为占位符,并且将按顺序应用这些参数值。另外,返回值参数必须是添加到 Parameters 集合中的第一批参数。
OLE DB .NET Framework 数据提供程序和 ODBC .NET Framework 数据提供程序不支持在向 SQL 语句或存储过程传递参数时使用命名参数。在此情况下,必须使用问号 (?) 占位符,如以下示例所示。
SELECT * FROM Customers WHERE CustomerID = ? |
因此,向 Parameters 集合添加 Parameter 对象的顺序必须直接对应于该参数的 ? 占位符的位置。
派生参数信息
参数也可以使用 CommandBuilder 类从存储过程派生。SqlCommandBuilder 和 OleDbCommandBuilder 类都提供了静态方法 DeriveParameters,该静态方法将自动使用存储过程中的参数信息填充 Command 对象的 Parameters 集合。请注意,DeriveParameters 将重写 Command 的任何现有参数信息。
派生参数信息时需要经历一个到数据源的附加行程,以获取参数信息。如果参数信息在设计时是已知的,则可以通过显式设置参数来提高应用程序的性能。
以下代码示例显示如何使用 CommandBuilder.DeriveParameters 来填充 Command 对象的 Parameters 集合。
- // Assumes that connection is a valid SqlConnection object.
- SqlCommand salesCommand = new SqlCommand("Sales By Year", connection);
- salesCommand.CommandType = CommandType.StoredProcedure;
- connection.Open();
- SqlCommandBuilder.DeriveParameters(salesCommand);
- connection.Close();