Como obter a última linha de identidade inserida ao usar em vez de acionar


9

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?


insertedmas nenhuma linha inserida quando um INSTEAD OFgatilhos de gatilho.
ypercubeᵀᴹ

Verifique esta questão SO: pode ajudar. stackoverflow.com/q/908257/27535
gbn

Você tem que escolher Selecionar ID, .. de Inserido, aqui Scope_Identity, @@ A identidade não funcionará

Respostas:


8

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?


Eu quero controlar a integridade dos dados da linha inserida. antes de salvá-los. Se os dados não estiverem bons, levanto uma mensagem proporcional ao erro.
lotfi Mehdi

2
Você está descrevendo uma chave estrangeira. Deve ser responsabilidade do aplicativo inserir na tabela filho, não um gatilho. Fazer isso de um gatilho é um design ruim e, de qualquer maneira, pode ser feito a partir de um gatilho AFTER normal. Um gatilho posterior pode gerar erros e causar reversão, que é a melhor opção do que um gatilho em vez de gatilho.
Remus Rusanu

11
Que noção absurda - "em vez de gatilhos é um cheiro sério de código"? Eles são muito úteis em comparação com um gatilho posterior - onde, se suas regras de negócios forem violadas, você executou o trabalho duas vezes - inseriu as linhas e as revertiu. Um gatilho em vez de um gatilho pode impedir que qualquer trabalho aconteça se suas regras de negócios não puderem ser aplicadas com DRI normal ou outras restrições.
Aaron Bertrand

11
Enquanto "em vez de gatilhos é um cheiro sério de código", não é uma regra estrita, é baseado em possíveis problemas reais que podem causar em um sistema completo. Em geral, as violações de regras de negócios nunca devem ocorrer no sistema, muito menos chegar ao nível do banco de dados. Nesse caso, uma validação de regra no gatilho é apropriada apenas como último mecanismo de defesa, caso haja um furo no sistema.
Alireza

4
A integridade declarativa é sempre melhor que um gatilho. Um gatilho posterior é sempre melhor que um gatilho em vez de gatilho. Em vez de gatilhos, eles têm um comportamento "descolado" em muitas situações, são opacos para acessar otimizações de caminho no DML, fazem com que os níveis de isolamento se comportem de maneira irregular. Em vez de gatilhos gritarem 'Eu deveria ter sido um procedimento armazenado de acesso'. E eu não compro o argumento 'faça o trabalho duas vezes', otimizar o caminho da exceção não deve influenciar o design, especialmente ao custo de diminuir o caminho frequente .
Remus Rusanu

12

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 @@IDENTITYou de IDENT_CURRENT()qualquer maneira. E SCOPE_IDENTITYdeve 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_IDENTITYvocê definiria para sua variável?


Como eu salvo o resultado do registro inserido na tabela variável para uso posterior.
lotfi Mehdi

@mehdi você pode definir "mais tarde"? E você não pode adicionar colunas à variável da tabela que eu já declarei acima?
Aaron Bertrand

3
Eu amo seus nomes de mesa.
Dan Esparza

-1

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>
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.