我正在使用C#桌面应用程序。我想使用存储过程(插入查询)将新记录添加到数据表中。我需要返回主键,该主键是一个身份插入(bigint
),以避免再次往返数据库。我已经搜索了几个小时的MS Help(less)文件,却发现如何设置存储过程的out参数或如何获取返回值一无所获。
答案 0 :(得分:1)
您想要的是一个OUTPUT
参数。我不是C#开发人员,因此我省略了C#方面,并链接了一个答案:
--Sample Table
CREATE TABLE dbo.YourTable (ID bigint IDENTITY,
SomeColumn varchar(20));
GO
--Sample SP
CREATE PROC dbo.InsertYourTable @SomeColumn varchar(20), @ID bigint OUTPUT AS
BEGIN
DECLARE @IDt table (ID bigint);
INSERT INTO dbo.YourTable(SomeColumn)
OUTPUT inserted.ID INTO @IDt
VALUES(@SomeColumn);
SET @ID = (SELECT ID FROM @IDt);
END;
GO
--Sample EXEC of proc and PRINT of OUTPUT value of ID
DECLARE @SomeColumn varchar(20) = 'abc', @ID bigint;
EXEC dbo.InsertYourTable @SomeColumn = @SomeColumn,
@ID = @ID OUTPUT;
PRINT @ID;
使用此answer,我认为c#将是:
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add("@SomeColumn",SqlDbType.VarChar,20);
cmd.Parameters["@SomeColumn"].Value = MyColumn;
cmd.Parameters.Add("@ID",SqlDbType.int).Direction = ParameterDirection.Output;
答案 1 :(得分:0)
给我的印象是您正试图从三个往返行程中走出来,像这样:
INSERT => SELECT to get key => OTHER INSERT using previous key
到两个
INSERT returns the key => OTHER INSERT using previous key
我们可以做得更好。
解决此问题的一种方法是在C#中的sql字符串中发送多个命令。因此,您最终得到了这样的结果,该结果达到了避免对数据库进行额外往返的目的:
string sql = @"
DECLARE @ID int;
EXEC InsertProcedure;
SELECT @ID = scope_identity();
INSERT INTO OtherTable VALUES (@ID);";
using (var cn = new SqlConnection("connection string"))
using (var cmd = new SqlCommand(sql, cn))
{
cn.Open();
cmd.ExecuteNonQuery();
}
或者,也许您只想在应用程序中使用该键,因此您可以继续使用记录并通过该新的聚集索引值进行快速查找。在这种情况下,您仍然可以这样:
string sql = @"
DECLARE @ID int;
EXEC InsertProcedure;
SELECT scope_identity();";
using (var cn = new SqlConnection("connection string"))
using (var cmd = new SqlCommand(sql, cn))
{
cn.Open();
return (int)cmd.ExecuteScalar();
}
请务必小心,存储过程本身是否有任何未解决的选择查询,在这种情况下,您需要使用ExecuteReader()
以及NextResult()
方法在{{1}之间进行切换}查询结果。
当然,它可能比实际代码要多得多,在实际代码中,您需要插入新数据的参数,但这提供了一般概念。
答案 2 :(得分:0)
在INSERT上使用OUTPUT子句很棒,如果需要捕获多行批处理中的标识值,则必不可少。但是,对于SQL初学者来说,代码要复杂一些,对于这个特定的问题,它可能与存储过程的OUTPUT parameter 混淆,这是一个完全无关的概念。
但是对于单行插入,SCOPE_IDENTITY函数可以很好地工作并且易于使用。
以下是Larnu's stored proc的一个版本,使用的是SCOPE_IDENTITY:
CREATE PROC dbo.InsertYourTable @SomeColumn varchar(20), @ID bigint OUTPUT AS
BEGIN
INSERT INTO dbo.YourTable(SomeColumn)
VALUES(@SomeColumn);
SET @ID = SCOPE_IDENTITY();
END;
答案 3 :(得分:0)
在大家的帮助下,我终于弄清楚了。我修改了存储过程,如下所示:
//存储过程
```` -- Add the parameters for the stored procedure here
````@Vendorcode nvarchar(17) = ''
````, @Name nvarchar(60) = ''
````...
````, @ID bigint output --<<<<<<<<Added this line
````AS
````BEGIN
```` -- SET NOCOUNT ON added to prevent extra result sets from
```` -- interfering with SELECT statements.
```` SET NOCOUNT ON;
```` -- Insert statements for procedure here
````INSERT INTO APVendorShipTo
```` (Vendorcode, [Name], ...)
````VALUES (@Vendorcode, @Name,...)
````Select @ID = SCOPE_IDENTITY(); -- <<<<<<<< Added this line
````END
*//end Stored Procedure*
----------
----------
*//C# Code in Desktop App*
````try
````{
````string connString = AdoHelper.ConnectionString;
````var myConnection = new SqlConnection(connString);
````var myCommand = new SqlCommand();
````using (myConnection)
````{
```` myConnection.Open();
```` myCommand.Connection = myConnection;
```` myCommand.CommandType = CommandType.StoredProcedure;
```` myCommand.CommandTimeout = 540;
```` myCommand.CommandText = "APVendorShipToAddNew";
```` myCommand.Parameters.AddWithValue(parameterName: "@Vendorcode", value:
this.txtAcctNo.Text);
```` myCommand.Parameters.AddWithValue(parameterName: "@Name", value: this.txtShipName.Text);
-- left out the rest of the parameters
--//Added the line below to retrieve the Identity Insert value from the query
````myCommand.Parameters.Add("@ID", SqlDbType.BigInt).Direction = ParameterDirection.Output;
````myCommand.ExecuteNonQuery();
--//Added next line to convert the returned value to a usable value in my program.
````liID = Convert.ToInt64(myCommand.Parameters["@ID"].Value);
````MessageBox.Show(Convert.ToString(liID));
--//Showed correct value Now available to my code
````return true;
````}