访问存储过程输出参数

时间:2016-06-13 10:13:48

标签: stored-procedures sql-server-2012 ado.net

我有一些使用datareader访问存储过程的代码,它返回一些输出参数和结果集。使用使用块创建datareader。

问题是我有时得到一个"对象引用未设置为对象的实例"在尝试访问输出参数时。我知道,如果在尝试访问输出参数时未关闭datareader,则通常会收到此错误。但是,因为在using块中访问了datareader,并且访问输出参数的代码在using块之外,所以参数永远不应为null。

这怎么可能?

SqlCommand command = new SqlCommand();
command.CommandText = "stored proc";

CommandBehavior commandBehavior = new CommandBehavior();

using (var reader = command.ExecuteReader(commandBehavior))
{
    while(reader.Read())
    {
        //access record values
    }
}

var param1 = command.Parameters["firstParam"].Value;  //<-- null reference error here

为简洁起见,我省略了一些代码。

代码和SQL服务器在VM上运行。

其他相关事实:C#.Net Framework 4.0,SQL Server 2012

5 个答案:

答案 0 :(得分:0)

您的代码结构看起来正确,这使我考虑可能存在于您的省略代码或存储过程中的原因。如果你已经检查了这些,我很抱歉。

  1. 对于某些查询,SQL存储过程是否为参数值返回null?

  2. 在省略的代码中,是否有任何更改了commandBehavior - 如果行为设置为CloseConnection,那么就有你的理由。

    顺便说一句。在您的内容中创建和使用commandBahavior()是不必要的 - 您拥有的是您的代码与reader = command.ExecuteReader()完全相同

  3. 您是否在command.Parameters["firstParam"]之前初始化command.ExecuteReader(),因为它设置了direction = output和正确的类型。

  4. 您是否为某些存储过程运行返回多个记录集?我相信参数在这种情况下会受到干扰,尽管我从来没有亲身体验过这一点

答案 1 :(得分:0)

请尝试以下代码,我已经测试过它工作正常。

SqlConnection con = new SqlConnection("Data Source=local;Initial Catalog=AdventureWorks;Integrated Security=SSPI;");
            SqlCommand command = new SqlCommand("Test",con);
            if (con.State == ConnectionState.Closed)
            {
                con.Open();
            }
            command.Parameters.AddWithValue("@parm1", "Hi");
            command.Parameters.Add("@parm2",SqlDbType.VarChar,500).Value = "";
            command.Parameters["@parm2"].Direction = ParameterDirection.Output;
            command.CommandType = CommandType.StoredProcedure;
            //CommandBehavior commandBehavior = new CommandBehavior();
            var parm2 = "";
            using (SqlDataReader reader = command.ExecuteReader())
            {
                while (reader.Read())
                {
                    //access record values
                }
                reader.Close();
                parm2 = Convert.ToString(command.Parameters["@parm2"].Value);
            }

SP:

CREATE PROCEDURE Test
@parm1 varchar(100),
@parm2 Varchar(200) = '' OUTPUT 
AS
BEGIN
    SELECT 1 AS parm1
    SELECT @parm2 = 'Shakti Singh'
END

答案 2 :(得分:0)

可能你的代码是正确的,你只需要在你提到的行上处理null,请尝试用以下代码替换该行。

var param1 = Convert.ToString(command.Parameters["firstParam"].Value);

答案 3 :(得分:0)

使用&#39;作为&#39;字符串关键字

command.Parameters["@parm2"].Value as string

答案 4 :(得分:0)

我能够通过在数据库上运行SQL分析器来跟踪问题。我很幸运地发现了一个错误。检查SQL日志显示存在死锁。但是,应用程序未收到错误。为了模拟错误,请尝试以下存储过程(从@Shakti复制):

CREATE PROCEDURE Test
@parm1 varchar(100),
@parm2 Varchar(200) = '' OUTPUT 
AS
BEGIN
    SELECT 1 AS parm1
    SELECT * FROM some_table
    SELECT @parm2 = 'Shakti Singh' 
    THROW 1,'Deadlock Error!',1   --error number not important, any error here will simulate the problem, in my case a deadlock
END

在应用程序中,您将能够读取数据读取器而不会出现任何错误,但您将无法访问输出参数。但是,如果您在SELECT *之前抛出错误,应用程序将收到错误,但您显然无法通读数据读取器。