Search code examples
c#t-sqlado.netsqlclient

Why is calling T-SQL INSERT with SELECT @@IDENTITY inserting duplicates?


I have a table with the following definition:

CREATE TABLE [dbo].[speech](
    [id] [int] IDENTITY(1,1) NOT NULL,
    [speaker] [int] NOT NULL,
    [speech_date] [date] NOT NULL,
    [subject] [varchar](250) NULL,
 CONSTRAINT [PK_speech] PRIMARY KEY CLUSTERED 
(
    [id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]

When adding a new speech, I am using this stored procedure:

CREATE PROCEDURE [dbo].[add_speech] 
      @speaker int
    , @speak_date date
    , @subject varchar(250)
AS
BEGIN
    INSERT INTO [dbo].[speech]
               ([speaker]
               ,[speech_date]
               ,[subject])
         VALUES
               (@speaker
               ,@speak_date
               ,@subject);

    SELECT CAST(@@IDENTITY AS int);
END

If I run the SProc from SSMS only one insert occurs, and the new Identity key is returned as expected. But when I run the following code in my application, two duplicate rows are inserted! With different identity keys, of course, and the identity returned is the second one.

affectedCount = command.ExecuteNonQuery();

if (affectedCount > 0) 
{ 
    succeeded = true;
    newID = (int)command.ExecuteScalar();
}

But, if I don't execute the command.ExecuteScalar() in the C# code to get the @@IDENTITY, a duplicate is not created!

What is going on?


Solution

  • You executed it twice - once via ExecuteNonQuery and once via ExecuteScalar. Don't do that! Just use ExecuteScalar (since it returns one row and one column). If you explicitly need the rowcount, ExecuteReader provides that via RecordsAffected - or select @@rowcount as a second column (but then you still can't use ExecuteScalar, because: 2 columns)