在 C# 中使用存储过程输出参数
Posted
技术标签:
【中文标题】在 C# 中使用存储过程输出参数【英文标题】:Using stored procedure output parameters in C# 【发布时间】:2012-06-09 23:18:16 【问题描述】:我在将输出参数从 Sql Server 存储过程返回到 C# 变量时遇到问题。我已经阅读了有关此的其他帖子,不仅在此处,而且在其他站点上,但我无法使其正常工作。这是我目前拥有的。目前我只是想打印返回的值。以下代码返回一个空值。我试图返回的是主键。我尝试过使用@@IDENTITY
和SCOPE_INDENTITY()
(即SET @NewId = SCOPE_IDENTITY()
)。
存储过程:
CREATE PROCEDURE usp_InsertContract
@ContractNumber varchar(7),
@NewId int OUTPUT
AS
BEGIN
INSERT into [dbo].[Contracts] (ContractNumber)
VALUES (@ContractNumber)
Select @NewId = Id From [dbo].[Contracts] where ContractNumber = @ContractNumber
END
打开数据库:
pvConnectionString = "Server = Desktop-PC\\SQLEXPRESS; Database = PVDatabase; User ID = sa;
PASSWORD = *******; Trusted_Connection = True;";
try
pvConnection = new SqlConnection(pvConnectionString);
pvConnection.Open();
catch (Exception e)
databaseError = true;
执行命令:
pvCommand = new SqlCommand("usp_InsertContract", pvConnection);
pvCommand.Transaction = pvTransaction;
pvCommand.CommandType = CommandType.StoredProcedure;
pvCommand.Parameters.Clear();
pvCommand.Parameters.Add(new SqlParameter("@ContractNumber", contractNumber));
SqlParameter pvNewId = new SqlParameter();
pvNewId.ParameterName = "@NewId";
pvNewId.DbType = DbType.Int32;
pvNewId.Direction = ParameterDirection.Output;
pvCommand.Parameters.Add(pvNewId);
try
sqlRows = pvCommand.ExecuteNonQuery();
if (sqlRows > 0)
Debug.Print("New Id Inserted = ",
pvCommand.Parameters["@NewId"].Value.ToString());
catch (Exception e)
Debug.Print("Insert Exception Type: 0", e.GetType());
Debug.Print(" Message: 0", e.Message);
【问题讨论】:
我是否使用 set 命令来执行此操作? SET NewId = SCOPE_IDENTITY()?我用以下内容替换了 select 语句...SET @NewId = SCOPE_IDENTITY() 并且我仍然收到一个空值。 是的,我可以看到数据库中的行。 我已经在代码中添加了连接的打开和命令的创建。 能否在读取输出参数之前尝试提交事务? 【参考方案1】:我稍微修改了你的存储过程(使用SCOPE_IDENTITY
),它看起来像这样:
CREATE PROCEDURE usp_InsertContract
@ContractNumber varchar(7),
@NewId int OUTPUT
AS
BEGIN
INSERT INTO [dbo].[Contracts] (ContractNumber)
VALUES (@ContractNumber)
SELECT @NewId = SCOPE_IDENTITY()
END
我试过了,它工作得很好(使用修改后的存储过程):
// define connection and command, in using blocks to ensure disposal
using(SqlConnection conn = new SqlConnection(pvConnectionString ))
using(SqlCommand cmd = new SqlCommand("dbo.usp_InsertContract", conn))
cmd.CommandType = CommandType.StoredProcedure;
// set up the parameters
cmd.Parameters.Add("@ContractNumber", SqlDbType.VarChar, 7);
cmd.Parameters.Add("@NewId", SqlDbType.Int).Direction = ParameterDirection.Output;
// set parameter values
cmd.Parameters["@ContractNumber"].Value = contractNumber;
// open connection and execute stored procedure
conn.Open();
cmd.ExecuteNonQuery();
// read output value from @NewId
int contractID = Convert.ToInt32(cmd.Parameters["@NewId"].Value);
conn.Close();
这也适用于您的环境吗?我不能说为什么你的原始代码不起作用 - 但是当我在这里执行此操作时,VS2010 和 SQL Server 2008 R2,它可以完美地工作......
如果您没有取回值 - 那么我怀疑您的表 Contracts
可能实际上没有包含 IDENTITY
属性的列。
【讨论】:
谢谢!感谢您在多年后为我们这些谷歌搜索的人回答这个问题。 :-) @marc_s 如果 Varchar 输出的大小未知,那么如何解决该问题。 cmd.Parameters.Add("@NewId", SqlDbType.Int).Direction = ParameterDirection.Output;需要改成 cmd.Parameters.AddWithValue("@NewId", SqlDbType.Int).Direction = ParameterDirection.Output;这是因为它已经贬值了 @user3569147:绝对不是!!您应该查看Can we stop using AddWithValue() already? 并停止使用.AddWithValue()
- 它会导致意想不到和令人惊讶的结果...跨度>
【参考方案2】:
在更改存储过程之前,请检查当前存储过程的输出。在 SQL Server Management 中运行以下命令:
DECLARE @NewId int
EXEC @return_value = [dbo].[usp_InsertContract]
N'Gary',
@NewId OUTPUT
SELECT @NewId
看看它返回了什么。这可能会给您一些提示,说明您的 out 参数未填充的原因。
【讨论】:
这只是作为一个答案,但可能应该是一个评论,但是由于多个 @ 字符的使用,我无法转换它(即使是 mods 也被拒绝了),我不能打扰编辑它以使其工作。 :)【参考方案3】:存储过程…………
CREATE PROCEDURE usp_InsertContract
@ContractNumber varchar(7)
AS
BEGIN
INSERT into [dbo].[Contracts] (ContractNumber)
VALUES (@ContractNumber)
SELECT SCOPE_IDENTITY() AS [SCOPE_IDENTITY]
END
C#
pvCommand.CommandType = CommandType.StoredProcedure;
pvCommand.Parameters.Clear();
pvCommand.Parameters.Add(new SqlParameter("@ContractNumber", contractNumber));
object uniqueId;
int id;
try
uniqueId = pvCommand.ExecuteScalar();
id = Convert.ToInt32(uniqueId);
catch (Exception e)
Debug.Print(" Message: 0", e.Message);
编辑:“我仍然得到一个 DBNull 值....对象不能从 DBNull 转换为其他类型。我明天再处理这个问题。我要去我的另一个工作,”
我认为您的 SQL 表中的 Id 列不是标识列。
【讨论】:
但这并不能回答为什么新 id 的输出参数返回 null 的问题。使用ExecuteScalar
,您可以检索返回值而不是输出参数。
进行此更改时,我还会收到以下错误...对象引用未设置为对象的实例。
那是因为该参数在SQL中称为SCOPE_IDENTITY; C# 仍在寻找名为@ContractNumber 的参数。
ContractNumber 是要添加到表中的值。主键称为 Id。
ExecuteScalar 返回一个对象,而不是一个 int。执行代码时收到异常。【参考方案4】:
我也遇到过类似的问题,先关闭连接,再读取参数,效果很好。
您可以在读取输出参数之前使用pvConnection.Close();
尝试
pvConnection = new SqlConnection(pvConnectionString);
pvConnection.Open();
捕获(异常 e)
数据库错误=真;
pvCommand = new SqlCommand("usp_InsertContract", pvConnection);
pvCommand.Transaction = pvTransaction;
pvCommand.CommandType = CommandType.StoredProcedure;
pvCommand.Parameters.Clear();
pvCommand.Parameters.Add(new SqlParameter("@ContractNumber", contractNumber));
SqlParameter pvNewId = new SqlParameter();
pvNewId.ParameterName = "@NewId";
pvNewId.DbType = DbType.Int32;
pvNewId.Direction = ParameterDirection.Output;
pvCommand.Parameters.Add(pvNewId);
try
sqlRows = pvCommand.ExecuteNonQuery();
pvConnection.Close();
if (sqlRows > 0)
Debug.Print("New Id Inserted = ",
pvCommand.Parameters["@NewId"].Value.ToString());
catch (Exception e)
Debug.Print("Insert Exception Type: 0", e.GetType());
Debug.Print(" Message: 0", e.Message);
【讨论】:
Mostafa,你能把这段代码分享给我们吗? 对不起,我没听懂你的意思! 没问题 :-) 我看到你在 7 月份用代码编辑了答案。谢谢。【参考方案5】:在您的 C# 代码中,您将事务用于命令。 只需提交事务,然后访问您的参数值,您将获得该值。 为我工作。 :)
【讨论】:
以上是关于在 C# 中使用存储过程输出参数的主要内容,如果未能解决你的问题,请参考以下文章
C#获取存储过程的 Return返回值和Output输出参数值