views:

70

answers:

7

How can I get id after an INSERT in SQL Server ?

For my insert, I use context.ExecuteStoreCommand()

Warning: I have a multi-threaded application which inserts "at the same time" some data in the same table.

A: 

I think you can write up a stored proc which has an in/out parameter, and then grab the value from the parameter.

rlee923
A: 

Try this

@@identity

below the sample code

strSQL = "INSERT INTO tablename (name) VALUES (@name);SELECT @@Identity"
SQLCommand.CommandText = strSQL
Id = SQLCommand.ExecuteScalar()
Ramesh Vel
This will not be thread safe.
Numenor
@Numenor, How this is not thread safe...??
Ramesh Vel
@Numenor - what are you talking about? That is perfectly thread safe, since both commands are being executed in a single query.
Damien_The_Unbeliever
@Patrice Pezillier, how do you say this is not thread safe.. did you check the insert statement at all??
Ramesh Vel
Downvoters, come on give me the reason??
Ramesh Vel
@Ramesh - When retrieving Identity values in MS SQL Server you should always use `Scope_Identity()` not `@@Identity`. Scope_Identity returns the identity value for the current scope where as @@Identity returns the last inserted identity. Which may or may not have been inserted in the current scope. See http://msdn.microsoft.com/en-us/library/ms190315.aspx for examples
Barry
(Didn't downvote) - SCOPE_IDENTITY is to be preferred over @@IDENTITY, mostly because of issues with triggers. But those claiming it's not thread safe are also mistaken, and are probably thinking of IDENT_CURRENT
Damien_The_Unbeliever
@Barry, thanks for the link, i understand that. But in this scenario the scope is single, so it wont cause any problems....
Ramesh Vel
@Damien_The_Unbeliever, yeah you are very much correct......
Ramesh Vel
@all: if some other thread using the same connection inserted some value to any table while your statements are being executed(you can not control this if your process is not the only process reaching the database), then @@Identity may return the other process's statements identity so it will cause a mistake.
Numenor
@Numenor - if some other thread is *somehow* executing statements on the *same* connection, then SCOPE_IDENTITY is equally likely to be screwed up.
Damien_The_Unbeliever
@Damien_The_Unbeliever: you are right about difference between @@IDENTTY and SCOPE_IDENTITY, i mistook it with IDENT_CURRENT.
Numenor
+3  A: 
SELECT SCOPE_IDENTITY()

Use this after your insert statement and it will return you the identity of inserted in your scope. You can assign this to variable or return it in an output parameter.

Numenor
What is a scope ? 2 threads are different scopes ?
Patrice Pezillier
yes they are. check http://msdn.microsoft.com/en-us/library/ms190315.aspx for detailed documentation for SCOPE_IDENTITY
Numenor
how does SCOPE_IDENTITY() differ from @@identity, SCOPE_IDENTITY() itself returns @@identity... and in my answer, i have returned the @@identity after the insert...
Ramesh Vel
SELECT SCOPE_IDENTITY() return null after my INSERT ?!context.ExecuteStoreQuery<int>("SELECT SCOPE_IDENTITY()")
Patrice Pezillier
you should call both your insert statement and Execute query in same context like: context.ExecuteStoreQuery<int>("insert into table values(...); SELECT SCOPE_IDENTITY()")
Numenor
+1  A: 

You should use Scope_Identity() for this scenario. This will return the Identity for the current scope. @@Identity returns the last inserted identity.

Take a look at Scope Identity on MSDN - there are examples of how @@Identity will return incorrect values compared to using Scope_Identity

Barry
+1  A: 

An alternative implementation method is to use the OUTPUT clause of the T-SQL language.

For example:

create table #tmpTable 
(
    ID int identity(1,1) not null primary key,
    SomeValue varchar(20) not null
);

insert #tmpTable
output INSERTED.ID
values('SomeTextData')

drop table #tmpTable;

From an overall solution design perspective I would advocate that you look to wrap your insertion logic into a Stored Procedure (returning the inserted record ID) that you call from your application source code.

John Sansom
A: 

I'm fairly sure you'll want to use the ObjectContext.ExecuteStoreQuery method if you need the identity value, rather than ObjectContext.ExecuteStoreCommand.

You'll need to use, as others have mentioned SCOPE_IDENTITY(), rather than @@IDENTITY as SCOPE_IDENTITY() returns the identity value for the currente execution scope wheras @@IDENTITY "Is a system function that returns the last-inserted identity value."

Something like this should do the trick:

using(var context = GetAContextThatsReadyToUse())
{
    var valueForColumn1 = 5;
    var result = ExecuteStoreQuery<int>("INSERT INTO table1 (Column1) VALUES ({0});SELECT SCOPE_IDENTITY()", valueForColumn1);

    foreach(var item in result)
    {
        // Should only return one result, which is the identity value inserted by ExecuteStoreQuery
        Console.WriteLine(item);
    }
}
Rob
A: 

I had lot of situations where something like 100 processes were writing at one table at a time. I didn't use SCOPE_IDENTITY() but were wrapping whole insert/ID fetch into an transaction, and there wasn't any problem with that approach.

Daniel Mošmondor