12

When I insert into tables using instead of triggers, @@Identity, IDENT_CURRENT('Table') and SCOPE_IDENTITY() return null. How I can get the last identity of inserted row?

Aaron Bertrand
182k28 gold badges406 silver badges625 bronze badges
asked Jun 6, 2012 at 6:45
1

3 Answers 3

9

With an INSTEAD_OF trigger it means no insert occurred yet. You cannot know the identity since it wasn't yet generated. Sneaking the value from metadata is possible (DBCC CHECKIDENT) but relying on it will not work correctly under concurrency and besides it requires elevated privileges.

INSTEAD_OF triggers are extremely seldom required and a serious code smell. Are you sure you need it? Can't you do the work with a regular AFTER trigger?

answered Jun 6, 2012 at 7:06
4
  • 2
    You are describing a foreign key. It should be the application responsibility to insert in the child table, not a trigger. Doing it from a trigger is bad design, and in anyway it can be done from a normal AFTER trigger. An after trigger can raise errors and cause rollback, which is the better option than an instead-of trigger. Commented Jun 6, 2012 at 7:36
  • instead of triggers are useful for instance to make a view that contains join updateable. Commented Jun 6, 2012 at 7:50
  • 3
    What an absurd notion - "instead of triggers are a serious code smell"? They are very useful compared to an after trigger - where, if your business rules are violated, you've done the work twice - you've inserted the rows and then you've rolled them back. An instead of trigger can prevent any of the work from happening if your business rules can't be enforced with normal DRI or other constraints. Commented Jun 6, 2012 at 12:09
  • 7
    Declarative integrity is always better than a trigger. An after trigger is always better than an instead of trigger. Instead-of triggers have 'funky' behavior in a lot of situations, they are opaque to access path optimizations in DML, they make isolation levels behave erratic. Instead-of triggers scream 'I should had been an access stored procedure instead'. And I don't buy the 'do the work twice' argument at all, optimizing the exception path should not influence the design, specially at the cost of the slowing the frequent path. Commented Jun 7, 2012 at 7:32
14

In your instead of trigger, you definitely can get the inserted value... but not until after you've performed the insert.

USE tempdb;
GO
CREATE TABLE dbo.SmellThis
(
 id INT IDENTITY(1,1),
 name VARCHAR(32)
);
GO
CREATE TRIGGER dbo.SmellThis_First
ON dbo.SmellThis
INSTEAD OF INSERT
AS
BEGIN
 SET NOCOUNT ON;
 DECLARE @ids TABLE(id INT);
 IF NOT EXISTS 
 (
 SELECT 1 FROM sys.objects AS o
 INNER JOIN inserted AS i
 ON o.name = i.name
 )
 INSERT dbo.SmellThis(name) 
 OUTPUT inserted.id INTO @ids
 SELECT name 
 FROM inserted;
 SELECT id FROM @ids;
END
GO
INSERT dbo.SmellThis(name) SELECT 'Remus';
GO

Results:

id
----
1

Now clean up:

DROP TABLE dbo.SmellThis;

As an aside, you should never, ever, ever be using @@IDENTITY or IDENT_CURRENT() anyway. And SCOPE_IDENTITY should be reserved for situations where you know only one row can ever be inserted. A common misconception with triggers is that they fire per row, like in other platforms, but in SQL Server they fire per operation - so a multi-row insert using VALUES(),(),() or INSERT...SELECT - which SCOPE_IDENTITY would you be setting to your variable?

answered Jun 6, 2012 at 12:13
0
-2

Main Problem : Trigger and Entity framework both work in diffrent scope. The problem is, that if you generate new PK value in trigger, it is different scope. Thus this command returns zero rows and EF will throw exception.

The solution is to add the following SELECT statement at the end of your Trigger:

SELECT * FROM deleted UNION ALL
SELECT * FROM inserted;

in place of * you can mention all the column name including

SELECT IDENT_CURRENT(‘tablename’) AS <IdentityColumnname>
answered Dec 27, 2017 at 6:23

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.