访问存储的 Proc 输出参数时出现间歇性空引用错误
Posted
技术标签:
【中文标题】访问存储的 Proc 输出参数时出现间歇性空引用错误【英文标题】:Intermittent Null Reference Errors When Accessing Stored Proc Output Parameter 【发布时间】:2016-06-13 10:13:48 【问题描述】:我有一些使用数据读取器访问存储过程的代码,它返回一些输出参数和一个结果集。数据读取器是使用 using 块创建的。
问题是我有时在尝试访问输出参数时得到“对象引用未设置为对象的实例”。我知道如果尝试访问输出参数时未关闭数据读取器,通常会收到此错误。但是,由于 datareader 是在 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
为简洁起见,我省略了一些代码。
代码和 SQL 服务器在 VM 上运行。
其他相关事实:C# .Net Framework 4.0、SQL Server 2012
【问题讨论】:
是的,我正在其他地方访问该值。 你能展示你的存储过程吗?如果您遇到死锁,我想我已经看到了这样的错误。 不幸的是,我无法显示确切的存储过程。但是,存储过程不做任何更新(只是选择),它使用快照隔离级别。我将尝试模拟死锁,看看这是否模拟了问题。谢谢。 【参考方案1】:可能你的代码是正确的,你只需要在你提到的那一行处理 null,请尝试用下面的代码替换那一行。
var param1 = Convert.ToString(command.Parameters["firstParam"].Value);
【讨论】:
请看上面的评论。正在处理 Null。【参考方案2】:请尝试以下代码,我已经测试它工作正常。
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
【讨论】:
我试过类似的代码。问题是错误间歇性地发生。如果代码有问题,错误总会出现。 你能从 SQL 中检查 firstParam 输出参数值,无论你在 C# 中遇到 NULL 引用错误的地方,我认为如果出现错误,你一定是从数据库中获取了一些奇怪的数据。【参考方案3】:使用'as'字符串关键字
command.Parameters["@parm2"].Value as string
【讨论】:
【参考方案4】:我能够通过在数据库上运行 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 * 之前抛出错误,应用程序将收到错误,但您显然无法通过数据读取器进行读取。
【讨论】:
实际的问题是在关闭datareader之前可能没有读取输出参数。 “Close 方法填充输出参数的值” - docs.microsoft.com/en-us/dotnet/api/…。所以僵局是一个红鲱鱼。【参考方案5】:您的代码结构看起来是正确的,这使我考虑了您省略的代码或存储过程中可能存在的可能原因。如果您已经检查过这些,我深表歉意。
SQL 存储过程是否为某些查询的参数值返回空值?
在省略的代码中,是否有任何更改了 commandBehavior - 如果行为设置为 CloseConnection
,那么这就是你的原因。
顺便说一句。在你的能力中创建和使用commandBahavior()
是不必要的 - 你所拥有的是你的代码与reader = command.ExecuteReader()
完全相同
您是否在 command.ExecuteReader()
之前初始化了 command.Parameters["firstParam"]
,因为它设置为 direction=output 并且类型正确。
您是否为存储过程的某些运行返回多个记录集?我相信在这种情况下参数会被打乱,尽管我从未亲身体验过,以了解某些情况
【讨论】:
1.我已经检查过了。我有代码来处理 DBNull 的返回值。我还模拟了返回空值。 2.commandBehaviour 设置为closeConnection。但这不会影响输出参数的读取。 3. 是的,输出参数已正确初始化。 4. 我检查了多个记录集的返回。这不是问题。如前所述,问题是间歇性的,因此有一些外部因素会影响结果。感谢您的帮助。 这种断断续续的性质确实令人费解。它表明参数正在丢失给垃圾收集器,但我并不完全相信。您是否有来自错误的堆栈跟踪。我最初想知道在哪个对象上检测到 null:cmd、参数或参数 ["以上是关于访问存储的 Proc 输出参数时出现间歇性空引用错误的主要内容,如果未能解决你的问题,请参考以下文章
在 Azure 网站中使用 Azure SDK 时出现间歇性 SSL/TLS 错误
Safari 访问受 Windows 集成身份验证 (aka NTLM) 保护的网站时出现问题