访问存储过程输出参数时出现间歇性空引用错误
Intermittent Null Reference Errors When Accessing Stored Proc Output Parameter
我有一些访问存储过程的代码,使用数据读取器,returns 一些输出参数和结果集。数据读取器是使用 using 块创建的。
问题是我 有时 在尝试访问输出参数时得到 "Object Reference not set to an instance of an object"。我知道如果在尝试访问输出参数时未关闭数据读取器,通常会收到此错误。但是,因为数据读取器是在 using 块中访问的,并且访问输出参数的代码在 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
为简洁起见,我省略了一些代码。
VM 上的代码和 SQL 服务器 运行。
其他相关事实:C# .Net Framework 4.0,SQL Server 2012
您的代码结构看起来是正确的,这使我考虑了您省略的代码或存储过程中可能存在的可能原因。如果您已经检查过这些内容,我深表歉意。
SQL 存储过程是否为某些查询的参数值返回空值?
在省略的代码中,是否有任何代码改变了 commandBehavior - 如果行为设置为 CloseConnection
,那么这就是你的原因。
顺便说一句。在您的 could 中创建和使用 commandBahavior()
是不必要的 - 您所拥有的是您的代码与 reader = command.ExecuteReader()
完全相同
您是否在 command.ExecuteReader()
之前初始化了 command.Parameters["firstParam"]
并设置了 direction=output 并且类型正确。
您是否为存储过程的某些运行返回多个记录集?我相信在这种情况下参数会被打乱,尽管我从来没有亲身经历过,无法确定
请尝试以下代码,我已经测试过它工作正常。
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
可能你的代码是正确的,你只需要在你提到的行上处理 null,请尝试用以下代码替换该行。
var param1 = Convert.ToString(command.Parameters["firstParam"].Value);
使用'as'字符串关键字
command.Parameters["@parm2"].Value as string
我能够通过数据库上的 运行 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
在应用程序中,您将能够毫无错误地读取数据 reader,但您将无法访问输出参数。但是,如果您在 SELECT * 之前抛出错误,应用程序将收到错误,但您显然无法读取数据 reader.
我有一些访问存储过程的代码,使用数据读取器,returns 一些输出参数和结果集。数据读取器是使用 using 块创建的。
问题是我 有时 在尝试访问输出参数时得到 "Object Reference not set to an instance of an object"。我知道如果在尝试访问输出参数时未关闭数据读取器,通常会收到此错误。但是,因为数据读取器是在 using 块中访问的,并且访问输出参数的代码在 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
为简洁起见,我省略了一些代码。
VM 上的代码和 SQL 服务器 运行。
其他相关事实:C# .Net Framework 4.0,SQL Server 2012
您的代码结构看起来是正确的,这使我考虑了您省略的代码或存储过程中可能存在的可能原因。如果您已经检查过这些内容,我深表歉意。
SQL 存储过程是否为某些查询的参数值返回空值?
在省略的代码中,是否有任何代码改变了 commandBehavior - 如果行为设置为
CloseConnection
,那么这就是你的原因。顺便说一句。在您的 could 中创建和使用
完全相同commandBahavior()
是不必要的 - 您所拥有的是您的代码与reader = command.ExecuteReader()
您是否在
command.ExecuteReader()
之前初始化了command.Parameters["firstParam"]
并设置了 direction=output 并且类型正确。您是否为存储过程的某些运行返回多个记录集?我相信在这种情况下参数会被打乱,尽管我从来没有亲身经历过,无法确定
请尝试以下代码,我已经测试过它工作正常。
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
可能你的代码是正确的,你只需要在你提到的行上处理 null,请尝试用以下代码替换该行。
var param1 = Convert.ToString(command.Parameters["firstParam"].Value);
使用'as'字符串关键字
command.Parameters["@parm2"].Value as string
我能够通过数据库上的 运行 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
在应用程序中,您将能够毫无错误地读取数据 reader,但您将无法访问输出参数。但是,如果您在 SELECT * 之前抛出错误,应用程序将收到错误,但您显然无法读取数据 reader.