C#:调用ExecuteNonQuery后不返回任何输出参数

时间:2018-03-06 18:24:58

标签: c# sql-server-2008 stored-procedures .net-3.5 executenonquery

从C#我在下面做:

SqlParameter[] Params= new SqlParameter[3];
Params[0] = new SqlParameter("SearchCode", strSearchCode); // strSearchCode is a string
Params[1] = new SqlParameter("@Error", 0);
Params[1].Direction = ParameterDirection.Output;
Params[2] = new SqlParameter("@OutputCode", "");
Params[2].Direction = ParameterDirection.Output;

int i = SqlHelper.ExecuteNonQuery(connectionString, CommandType.StoredProcedure, "MySP", Params);

int intError = Convert.ToInt32(Params[1].Value);
string strOutputCode = Convert.ToString(Params[2].Value);

SqlHelper是一个包含数据库查询方法的帮助器类,我只在这里发布调用中使用的那些:

public static int ExecuteNonQuery(string connectionString, CommandType commandType, string commandText, params SqlParameter[] commandParameters)
{
    if( connectionString == null || connectionString.Length == 0 ) throw new ArgumentNullException( "connectionString" );

    // Create & open a SqlConnection, and dispose of it after we are done
    using (SqlConnection connection = new SqlConnection(connectionString))
    {
        connection.Open();

        // Call the overload that takes a connection in place of the connection string
        return ExecuteNonQuery(connection, commandType, commandText, commandParameters);
    }
}

public static int ExecuteNonQuery(SqlConnection connection, CommandType commandType, string commandText, params SqlParameter[] commandParameters)
{   
    if( connection == null ) throw new ArgumentNullException( "connection" );

    // Create a command and prepare it for execution
    SqlCommand cmd = new SqlCommand();
    bool mustCloseConnection = false;
    PrepareCommand(cmd, connection, (SqlTransaction)null, commandType, commandText, commandParameters, out mustCloseConnection );

    // Finally, execute the command
    int retval = cmd.ExecuteNonQuery();

    // Detach the SqlParameters from the command object, so they can be used again
    cmd.Parameters.Clear();
    if( mustCloseConnection )
        connection.Close();
    return retval;
}

private static void PrepareCommand(SqlCommand command, SqlConnection connection, SqlTransaction transaction, CommandType commandType, string commandText, SqlParameter[] commandParameters, out bool mustCloseConnection )
{
    if( command == null ) throw new ArgumentNullException( "command" );
    if( commandText == null || commandText.Length == 0 ) throw new ArgumentNullException( "commandText" );

    // If the provided connection is not open, we will open it
    if (connection.State != ConnectionState.Open)
    {
        mustCloseConnection = true;
        connection.Open();
    }
    else
    {
        mustCloseConnection = false;
    }

    // Associate the connection with the command
    command.Connection = connection;

    int timeOut = new System.Data.SqlClient.SqlConnectionStringBuilder(connection.ConnectionString).ConnectTimeout;
    command.CommandTimeout = timeOut; //connection.ConnectionTimeout * 2;

    // Set the command text (stored procedure name or SQL statement)
    command.CommandText = commandText;

    // If we were provided a transaction, assign it
    if (transaction != null)
    {
        if( transaction.Connection == null ) throw new ArgumentException( "The transaction was rollbacked or commited, please provide an open transaction.", "transaction" );
        command.Transaction = transaction;
    }

    // Set the command type
    command.CommandType = commandType;

    // Attach the command parameters if they are provided
    if (commandParameters != null)
    {
        AttachParameters(command, commandParameters);
    }
    return;
}

private static void AttachParameters(SqlCommand command, SqlParameter[] commandParameters)
{
    if( command == null ) throw new ArgumentNullException( "command" );
    if( commandParameters != null )
    {
        foreach (SqlParameter p in commandParameters)
        {
            if( p != null )
            {
                // Check for derived output value with no value assigned
                if ( ( p.Direction == ParameterDirection.InputOutput || 
                    p.Direction == ParameterDirection.Input ) && 
                    (p.Value == null))
                {
                    p.Value = DBNull.Value;
                }
                command.Parameters.Add(p);
            }
        }
    }
}

我的存储过程如下所示:

CREATE PROCEDURE [dbo].[MySP] 
    @SearchCode char(10),
    @Error int OUTPUT,
    @OutputCode char(50) OUTPUT         

AS

    DECLARE @Flag1 bit
    DECLARE @IDate date
    DECLARE @FDate date
    DECLARE @TypeM tinyint

    SELECT @OutputCode=SomeField FROM SearchTable WHERE FieldToSearch=@SearchCode
    IF @@ROWCOUNT=0
    begin
        SET @Error=1
        RETURN
    end

    SELECT @Flag1=Flag_1, @TypeM=MyType FROM AnotherTable WHERE Condition1=@OutputCode
    IF @@ROWCOUNT=0
    begin
        SET @Error=2
        RETURN
    end 

    SELECT @IDate=InitDate, @FDate=FinalDate FROM AnotherTable2 WHERE Condition1=@OutputCode
    IF @@ROWCOUNT=0
    begin
        SET @Error=3
        RETURN
    end     

    SELECT SomeField From AnotherTable3 WHERE Condition1=SomeCondition
    IF @@ROWCOUNT=0
    begin
        SET @Error=4
        RETURN
    end 

    SELECT SomeField From AnotherTable4 WHERE Condition1=SomeCondition2
    IF @@ROWCOUNT=0
    begin
        SET @Error=5
        RETURN
    end 

    SET @Error=0

我遇到的问题是当我这样做时,没有从C#代码中读取输出参数@OutputCode

string strOutputCode = Convert.ToString(Params[2].Value);

strOutputCode包含"0"

如果是另一个输出参数:

int intError = Convert.ToInt32(Params[1].Value);

它返回ok,值为0,因为存储过程的执行正在正确执行,并且在存储过程中没有满足@@ROWCOUNT=0条件。

但是,如果我从SQL Server对同一个数据库启动存储过程:

DECLARE @OutputCode char(50)    
DECLARE @Error int 
DECLARE @SearchCode char(10) = '12003'

EXEC [dbo].[MySP] @SearchCode, @Error OUTPUT,  @OutputCode OUTPUT
select @Error, @OutputCode

然后我得到@OutputCode的正确值,该值是与"0"不同的字符串。

我确保了商店程序中的第一个查询:

SELECT @OutputCode=SomeField FROM SearchTable WHERE FieldToSearch=@SearchCode

正在正确执行并返回一行一列,因此@OutputCode被正确分配了值。

任何想法发生了什么?

1 个答案:

答案 0 :(得分:1)

问题在于我没有指定输出参数的大小。由于我只是将值作为空字符串传递,因此默认情况下SQL Server的大小为1个字符而不是50个。因此,从C#我收到第一个字符,在这种情况下,是" 0&# 34。

指定输出参数的大小可以解决问题:

Params[2] = new SqlParameter();
Params[2].SqlDbType = System.Data.SqlDbType.NVarChar;
Params[2].ParameterName = "@OutputCode";
Params[2].Direction = System.Data.ParameterDirection.Output;
Params[2].Size = 50;  // should be >=50
Params[2].Value = string.Empty;

备注: 如果输出参数小于50个字符,我们在末尾会收到空格,所以我们需要使用C#中的Trim函数删除末尾的空格。