C# 为什么SQL Server存储过程中的输出参数总是返回null?

C# 为什么SQL Server存储过程中的输出参数总是返回null?,c#,sql-server,stored-procedures,C#,Sql Server,Stored Procedures,我编写了一个C程序,它调用SQL Server存储过程从数据库中获取信息 C程序: public void testing(ref int pIMPORT_ID) { string sMessage = null; int sValue = 0; ADODB.Command cnnCmd = null; object resc; ModCommon.adodb_connect(); cnnCmd = new ADODB.Command();

我编写了一个C程序,它调用SQL Server存储过程从数据库中获取信息

C程序:

public void testing(ref int pIMPORT_ID)
{
    string sMessage = null;
    int sValue = 0;
    ADODB.Command cnnCmd = null;
    object resc;

    ModCommon.adodb_connect();

    cnnCmd = new ADODB.Command();
    cnnCmd.ActiveConnection = ModMain.gConn;
    cnnCmd.CommandType = ADODB.CommandTypeEnum.adCmdStoredProc;
    cnnCmd.CommandText = "sp_TEST";

    try
    {
        cnnCmd.Parameters.Append(cnnCmd.CreateParameter("RETURN_VALUE", ADODB.DataTypeEnum.adInteger, ADODB.ParameterDirectionEnum.adParamReturnValue));
        cnnCmd.Parameters.Append(cnnCmd.CreateParameter("IMPORT_ID", ADODB.DataTypeEnum.adInteger, ADODB.ParameterDirectionEnum.adParamInput));
        cnnCmd.Parameters.Append(cnnCmd.CreateParameter("MSG", ADODB.DataTypeEnum.adVarChar, ADODB.ParameterDirectionEnum.adParamOutput, 200));
        cnnCmd.Parameters.Refresh();

        cnnCmd.Parameters["@IMPORT_ID"].Value = pIMPORT_ID;

        cnnCmd.Execute(out resc);

        sMessage = cnnCmd.Parameters["@MSG"].Value;
        sValue = cnnCmd.Parameters["@RETURN_VALUE"].Value;

        ModMain.gConn.Close();
    }
    catch (Exception ex)
    {
        FileSystem.FileOpen(11, ModMain.strErrLogFile, OpenMode.Output);
        FileSystem.PrintLine(11, "*****");
        FileSystem.PrintLine(11, "Error occurs!");
        FileSystem.FileClose(11);
        System.Environment.Exit(0);
    }
}
在执行以下存储过程之后,我为sMessage获取{},为sValue获取null

但是在执行以下存储过程之后,与上面相同,但是使用execute@SQL注释后,对于sMessage,我得到的不是空的,对于sValue,我得到的是0,这是期望的结果

ALTER PROCEDURE [dbo].[sp_TEST_TEMP_TABLE]
    @IMPORT_ID int,
    @MSG varchar(200) output
AS
BEGIN
    DECLARE @SQL varchar(4000)
    DECLARE @cnt_B int = 0

    CREATE TABLE #TEMP(cnt int)

    SELECT @SQL = 'insert into #TEMP select count(*) from STAFF where IMPORT_ID = ' + STR(@IMPORT_ID)
    --exec (@SQL)

    IF @@ROWCOUNT > 0
        SET @MSG = 'NOT EMPTY'
    ELSE
        SET @MSG = 'EMPTY'

    DROP TABLE #TEMP

    RETURN 0
END
GO

为什么会这样?STAFF表不是空的。

在SSMS中执行存储过程并查找任何错误。对我来说,这是:

Msg 208,16级,状态1,第1行

无效的对象名称“STAFF”

动态SQL获取的数据库上下文完全可能与存储过程所在的数据库上下文不同。因此,按照流行程度的顺序:

确保您确实需要使用动态SQL。是的,每次您进入这个领域时都必须证明它是正确的,因为它使您的代码可能容易受到注入攻击。 使用数据库上下文开关预先编写动态语句。例如:

set@SQL='use'+quotenamedb_name+'; 将导入ID='+STR@IMPORT_ID;

参数化动态语句。这将需要舍弃exec以支持sys.sp_executesql,但下次尝试连接来自用户的字符串参数时,您会很高兴这样做

确保您动态触摸的任何对象都存在于当前数据库中,否则您将得到错误208,并且它具有相应的列错误207。
在SSMS中执行存储过程并查找任何错误。对我来说,这是:

Msg 208,16级,状态1,第1行

无效的对象名称“STAFF”

动态SQL获取的数据库上下文完全可能与存储过程所在的数据库上下文不同。因此,按照流行程度的顺序:

确保您确实需要使用动态SQL。是的,每次您进入这个领域时都必须证明它是正确的,因为它使您的代码可能容易受到注入攻击。 使用数据库上下文开关预先编写动态语句。例如:

set@SQL='use'+quotenamedb_name+'; 将导入ID='+STR@IMPORT_ID;

参数化动态语句。这将需要舍弃exec以支持sys.sp_executesql,但下次尝试连接来自用户的字符串参数时,您会很高兴这样做

确保您动态触摸的任何对象都存在于当前数据库中,否则您将得到错误208,并且它具有相应的列错误207。
我认为您不应该在本例中使用@ROWCOUNT,为什么不查询临时表以查看是否有行

我也不确定我是否理解您为什么要编写动态查询

您可以这样做:

DECLARE @cnt as int 
SELECT @cnt = count(*) from STAFF where IMPORT_ID = @IMPORT_ID
if (@cnt > 0) etc...

我认为您不应该在本例中使用@ROWCOUNT,为什么不查询临时表以查看是否有行

我也不确定我是否理解您为什么要编写动态查询

您可以这样做:

DECLARE @cnt as int 
SELECT @cnt = count(*) from STAFF where IMPORT_ID = @IMPORT_ID
if (@cnt > 0) etc...
旁注:存储过程不应使用sp_uu前缀。微软已经这样做了,而且你确实有可能在将来的某个时候发生名称冲突。最好只是简单地避免使用sp_u,并使用其他东西作为前缀——或者根本不使用前缀!旁注:存储过程不应使用sp_uu前缀。微软已经这样做了,而且你确实有可能在将来的某个时候发生名称冲突。最好只是简单地避免使用sp_u,并使用其他东西作为前缀——或者根本不使用前缀!