Quando eu inserir em tabelas usando em vez de gatilhos, @@Identity
, IDENT_CURRENT('Table')
e SCOPE_IDENTITY()
nulo retorno. Como posso obter a última identidade da linha inserida?
Quando eu inserir em tabelas usando em vez de gatilhos, @@Identity
, IDENT_CURRENT('Table')
e SCOPE_IDENTITY()
nulo retorno. Como posso obter a última identidade da linha inserida?
Respostas:
Com um gatilho INSTEAD_OF, significa que ainda não ocorreu nenhuma inserção. Você não pode conhecer a identidade, pois ela ainda não foi gerada. É possível ocultar o valor dos metadados ( DBCC CHECKIDENT
), mas confiar nele não funcionará corretamente em simultâneo e, além disso, requer privilégios elevados.
Os gatilhos INSTEAD_OF são extremamente raramente necessários e têm um cheiro sério ao código. Tem certeza de que precisa? Você não pode fazer o trabalho com um gatilho AFTER regular?
No seu gatilho, em vez do gatilho, você definitivamente pode obter o valor inserido ... mas não até depois de executar a inserção.
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
Resultados:
id
----
1
Agora limpe:
DROP TABLE dbo.SmellThis;
Como um aparte, você nunca, nunca, deve estar usando @@IDENTITY
ou de IDENT_CURRENT()
qualquer maneira. E SCOPE_IDENTITY
deve ser reservado para situações em que você sabe que apenas uma linha pode ser inserida. Um equívoco comum com os acionadores é que eles são acionados por linha, como em outras plataformas, mas no SQL Server eles são acionados por operação - portanto, uma inserção de várias linhas usando VALUES(),(),()
ou INSERT...SELECT
- qual SCOPE_IDENTITY
você definiria para sua variável?
Problema principal: A estrutura Trigger e Entity funciona em escopo diferente. O problema é que, se você gerar um novo valor de PK no gatilho, será um escopo diferente. Portanto, este comando retorna zero linhas e EF lançará uma exceção.
A solução é adicionar a seguinte instrução SELECT no final do seu gatilho:
SELECT * FROM deleted UNION ALL
SELECT * FROM inserted;
no lugar de *, você pode mencionar todo o nome da coluna, incluindo
SELECT IDENT_CURRENT(‘tablename’) AS <IdentityColumnname>
inserted
mas nenhuma linha inserida quando umINSTEAD OF
gatilhos de gatilho.