ADO.NET SqlCommand 没有为 SCOPE_IDENTITY() 返回正确的值

ADO.NET SqlCommand not returning correct value for SCOPE_IDENTITY()

我有一个简单的 table :

CREATE TABLE [MyTable]
(
    [ID] [INT] IDENTITY(1,1) NOT NULL,
    [NAME] [NVARCHAR](100) NOT NULL,
    [DATA] [NVARCHAR](max) NOT NULL,

    CONSTRAINT [PK_MyTable] 
        PRIMARY KEY CLUSTERED ([ID] ASC)
                    WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, 
                          IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, 
                          ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
GO

我有一个存储过程,它通过 SCOPE_IDENTITY()

在此 table 中插入一行并 returns PK IDENTITY 列的值
CREATE PROCEDURE [InsertMyTable] 
    @NAME NVARCHAR(100),
    @DATA NVARCHAR(MAX)  
AS
BEGIN
    INSERT INTO [MyTable] ([NAME], [DATA])
    VALUES (@NAME, @DATA)  

    RETURN SCOPE_IDENTITY()
END

我已经通过 SSMS 和其他工具测试了这个存储过程,它的行为符合预期。

每次以下脚本 运行,returned 值递增 1 :

DELETE FROM [MyTable]
GO

DECLARE @return INT

EXEC @return = [InsertMyTable] @NAME='MyName', @DATA='Data'

SELECT @return
GO

然而,当我使用 System.Data.SqlClient 在 C# 代码中执行类似操作时,存储过程 return 值始终为 1。它似乎并没有反映每次行是递增的标识删除并重新插入。

    using (var connection = new SqlConnection({connection-string}))
    using (var command = connection.CreateCommand())
    {
        command.CommandType = CommandType.Text;
        command.CommandText = "delete from [MyTable] where [NAME]='MyName'";

        connection.Open();

        command.ExecuteNonQuery();
    }

    using (var connection = new SqlConnection({connection-string}))
    using (var command = connection.CreateCommand())
    {
        command.CommandType = CommandType.StoredProcedure;
        command.CommandText = "InsertMyTable";

        command.Parameters.Add(new SqlParameter($"@NAME", "MyName"));
        command.Parameters.Add(new SqlParameter($"@DATA", "data"));

        connection.Open();

        var returnValue = command.ExecuteNonQuery();
    }

您的存储过程 return 作为存储过程 return 值的 ID,它应该只用于成功或失败,绝不能用于数据。

SqlCommand.ExecuteNonQuery() returns 已执行批处理的所有行计数消息的总数。

你应该使用输出参数

CREATE PROCEDURE [InsertMyTable] 
  @NAME NVARCHAR(100)
, @DATA NVARCHAR(MAX) 
, @ID INT OUTPUT
AS
BEGIN
INSERT INTO [MyTable]
           ([NAME]
           ,[DATA])
     VALUES
           ( @NAME
           , @DATA)  
set @ID = SCOPE_IDENTITY()
END

或使用结果集,并使用 SqlCommand.ExecuteScalar() 或 SqlCommand.ExecuteReader() 获取值。

CREATE PROCEDURE [InsertMyTable] 
  @NAME NVARCHAR(100)
, @DATA NVARCHAR(MAX)  
AS
BEGIN
INSERT INTO [MyTable]
           ([NAME]
           ,[DATA])
     VALUES
           ( @NAME
           , @DATA)  
SELECT SCOPE_IDENTITY() ID
END

您可以通过绑定一个额外的 SqlParameter 使现有的工作正常进行,但这是一种不好的做法。