【问题标题】:Execute SqlCommand without providing values to parameters在不向参数提供值的情况下执行 SqlCommand
【发布时间】:2021-12-29 12:32:57
【问题描述】:

我的数据库中有一个存储过程:

ALTER PROCEDURE [dbo].[SP_UPDATE_PARAMS]
    (@ELEMENT NUMERIC (10),
     @NUM_PARAM_OP_DINT NUMERIC (3,0) OUTPUT,
     @NUM_PARAM_OP_REAL NUMERIC (3,0) OUTPUT,
     @NUM_PARAM_LL NUMERIC (3,0) OUTPUT,
     .... + other 500 output params

该过程根据@Element 的值为每个值生成一个输出。否则返回值 0。

所以,在我的 C# 代码中,我尝试使用它:

....
using (SqlConnection connection = new SqlConnection(connectString))
{
    connection.Open();

    using (SqlCommand cmd = new SqlCommand("[dbo].[SP_UPDATE_PARAMS]", connection))
    {
        cmd.CommandType = CommandType.StoredProcedure;
        cmd.Parameters.AddWithValue("@ELEMENT", SqlDbType.Int).Value = element;

        SqlDataReader rdr = cmd.ExecuteReader();
.....

但我收到此错误:

存储过程或函数 [dbo].[SP_UPDATE_PARAMS] 需要 @NUM_PARAM_OP_DINT 未提供的参数

如果我没有为[dbo].[SP_UPDATE_PARAMS] 的 504 个值中的每一个提供值(即使它们是输出),就会发生这种情况

我尝试过使用

foreach (IDataParameter param in cmd.Parameters)
{
    param.Value = DBNull.Value;
}

foreach (SqlParameter parameter in cmd.Parameters)
{
    parameter.Value = DBNull.Value;
}

打电话之前

SqlDataReader rdr = cmd.ExecuteReader();

但它们都不行,因为cmd.Parameters 在(我猜)cmd.ExecuteReader() 被执行之前为空。

我怎样才能避免必须为所有参数提供一个值,或者让它们都为空?

【问题讨论】:

  • 输出并不意味着参数是由存储过程为您创建的。您仍然需要创建它们,然后存储过程可以设置每个参数中的值,以便您在执行命令后检索
  • 旁注:您应该为您的存储过程使用sp_ 前缀。微软有reserved that prefix for its own use (see Naming Stored Procedures),你确实会在未来某个时候冒着名称冲突的风险。 It's also bad for your stored procedure performance。最好只是简单地避免 sp_ 并使用其他东西作为前缀 - 或者根本不使用前缀!
  • 500 个输出参数是真正的代码异味。它们不能被合并,或者您应该使用SELECT 返回一个常规结果集?另请注意,如果您为参数创建默认值但不传递它们,SqlCommand 将不会返回它们

标签: c# .net sql-server sqlcommand


【解决方案1】:

如果您将空参数传递给 proc,则需要将参数声明为 NULL,例如

@ELEMENT NUMERIC (10) = NULL,
@NUM_PARAM_OP_DINT  NUMERIC (3,0) = NULL,
@NUM_PARAM_OP_REAL  NUMERIC (3,0) = NULL,
@NUM_PARAM_LL   NUMERIC (3,0) = NULL,

您仍然需要向 proc 提供参数,但取决于您实际希望为 null 的参数,传递 DBNull.Value

编辑:不要为了上帝的爱而使用AddWithValue。只需使用Add

【讨论】:

    【解决方案2】:

    cmd.Parameters 属性为空,您为尝试执行的过程添加参数。

    https://docs.microsoft.com/en-us/dotnet/api/system.data.sqlclient.sqlcommand.parameters?view=dotnet-plat-ext-6.0#property-value

    您可以为该存储过程的默认参数创建一个带有参数数组的对象,并将该对象作为您的参数传入。您仍然可以通过这种方式设置您的 @ELEMENT 值。

    https://docs.microsoft.com/en-us/dotnet/api/system.data.sqlclient.sqlparametercollection.addrange?view=dotnet-plat-ext-6.0

    另一种可能的解决方案,使您的存储过程输出参数可选

    ALTER PROCEDURE [dbo].[SP_UPDATE_PARAMS](@ELEMENT NUMERIC (10),
                                                    @NUM_PARAM_OP_DINT  NUMERIC (3,0) = NULL OUTPUT,
                                                    @NUM_PARAM_OP_REAL  NUMERIC (3,0) = NULL OUTPUT,
                                                    @NUM_PARAM_LL   NUMERIC (3,0) = NULL OUTPUT,
    

    【讨论】:

    • 所以答案是:不可能这样做。可能的解决方法是:1-) 初始化和传递值 2-) 修改过程以提供默认值。谢谢!
    • 在不了解您正在尝试做什么以及您正在使用的系统的情况下,这些似乎是使用该存储过程的最简单选择。如果 SP 需要这些参数,您必须提供它们。
    猜你喜欢
    • 2010-11-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-08-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-05-24
    相关资源
    最近更新 更多