当设置了 ReturnValue 时,SqlCommand 不发送 EXEC @return = Sproc
SqlCommand not sending `EXEC @return = Sproc` when `ReturnValue` is set
我有一个 SQL 服务器存储过程,它 return 有多个结果表,此外还总是 return 一个整数值,例如
CREATE PROCEDURE dbo.Foo
@someParameter varchar(100) = NULL,
@anotherParam date
AS
BEGIN
IF @anotherParam > GETDATE() BEGIN
RETURN 1
END
SELECT foo, bar FROM someTable WHERE blargh
SELECT baz FROM anotherTable WHERE blargh
RETURN 0
END
在 C# 中,我这样做:
using( DbCommand cmd = c.CreateCommand() ) {
// cmd is an instance of SqlCommand despite being cast to DbCommand
cmd.CommandText = "Foo";
cmd.CommandType = CommandType.StoredProcedure;
/* code that adds other parameters here */
IDataParameter returnParam = cmd.CreateParameter(); // returnParam is an instance of SqlParameter
returnParam.ParameterName = "@ReturnValue";
returnParam.Direction = ParameterDirection.ReturnValue;
returnParam.DbType = DbType.Int32;
cmd.Parameters.Add( paraReturn );
using( DbDataReader rdr = cmd.ExecuteReader() ) {
Int32 returnValue = (Int32)returnParam.Value; <-- exception here
}
}
SQL Server Profiler 显示以下命令已发送到服务器:
exec Foo @someParameter=N'1234ABCD',@anotherParam='2015-01-01 00:00:00'
它没有在任何地方添加 @ReturnValue
参数来捕获存储过程的 return 值。
相比之下,当我使用 SQL Server Management Studio 执行程序时,Profiler 显示这是发送到服务器:
DECLARE @return_value int
EXEC @return_value = Foo @someParameter=N'1234ABCD',@anotherParam='2015-01-01 00:00:00'
为什么?
啊,事实证明存储过程 中的 return 值是 returned:它是 "emitted" 匿名来自 SQL 不需要显式变量来捕获它的服务器(尽管如有必要,您仍然可以捕获它,如我给出的 SQL Server Management Studio 示例)。
因此,虽然 return 值存在,但 DbDataReader
不会填充 ParameterDirection.ReturnValue
参数 ,直到 reader 已关闭。
所以这有效:
IDataParameter returnParam = cmd.CreateParameter(); // returnParam is an instance of SqlParameter
returnParam.ParameterName = "@ReturnValue";
returnParam.Direction = ParameterDirection.ReturnValue;
returnParam.DbType = DbType.Int32;
cmd.Parameters.Add( paraReturn );
using( DbDataReader rdr = cmd.ExecuteReader() ) {
// do stuff
}
Int32 returnValue = (Int32)returnParam.Value;
但这不是:
...
using( DbDataReader rdr = cmd.ExecuteReader() ) {
Int32 returnValue = (Int32)returnParam.Value;
}
我有一个 SQL 服务器存储过程,它 return 有多个结果表,此外还总是 return 一个整数值,例如
CREATE PROCEDURE dbo.Foo
@someParameter varchar(100) = NULL,
@anotherParam date
AS
BEGIN
IF @anotherParam > GETDATE() BEGIN
RETURN 1
END
SELECT foo, bar FROM someTable WHERE blargh
SELECT baz FROM anotherTable WHERE blargh
RETURN 0
END
在 C# 中,我这样做:
using( DbCommand cmd = c.CreateCommand() ) {
// cmd is an instance of SqlCommand despite being cast to DbCommand
cmd.CommandText = "Foo";
cmd.CommandType = CommandType.StoredProcedure;
/* code that adds other parameters here */
IDataParameter returnParam = cmd.CreateParameter(); // returnParam is an instance of SqlParameter
returnParam.ParameterName = "@ReturnValue";
returnParam.Direction = ParameterDirection.ReturnValue;
returnParam.DbType = DbType.Int32;
cmd.Parameters.Add( paraReturn );
using( DbDataReader rdr = cmd.ExecuteReader() ) {
Int32 returnValue = (Int32)returnParam.Value; <-- exception here
}
}
SQL Server Profiler 显示以下命令已发送到服务器:
exec Foo @someParameter=N'1234ABCD',@anotherParam='2015-01-01 00:00:00'
它没有在任何地方添加 @ReturnValue
参数来捕获存储过程的 return 值。
相比之下,当我使用 SQL Server Management Studio 执行程序时,Profiler 显示这是发送到服务器:
DECLARE @return_value int
EXEC @return_value = Foo @someParameter=N'1234ABCD',@anotherParam='2015-01-01 00:00:00'
为什么?
啊,事实证明存储过程 中的 return 值是 returned:它是 "emitted" 匿名来自 SQL 不需要显式变量来捕获它的服务器(尽管如有必要,您仍然可以捕获它,如我给出的 SQL Server Management Studio 示例)。
因此,虽然 return 值存在,但 DbDataReader
不会填充 ParameterDirection.ReturnValue
参数 ,直到 reader 已关闭。
所以这有效:
IDataParameter returnParam = cmd.CreateParameter(); // returnParam is an instance of SqlParameter
returnParam.ParameterName = "@ReturnValue";
returnParam.Direction = ParameterDirection.ReturnValue;
returnParam.DbType = DbType.Int32;
cmd.Parameters.Add( paraReturn );
using( DbDataReader rdr = cmd.ExecuteReader() ) {
// do stuff
}
Int32 returnValue = (Int32)returnParam.Value;
但这不是:
...
using( DbDataReader rdr = cmd.ExecuteReader() ) {
Int32 returnValue = (Int32)returnParam.Value;
}