Come ottenere l'ultima riga di identità inserita quando si utilizza invece di trigger


9

Quando inserisco in tabelle utilizzando al posto di trigger, @@Identity, IDENT_CURRENT('Table')e SCOPE_IDENTITY()nulla di ritorno. Come posso ottenere l'ultima identità della riga inserita?


Non è insertedstata inserita alcuna riga quando si INSTEAD OFattiva un trigger.
ypercubeᵀᴹ

Controlla questa domanda SO: può aiutare. stackoverflow.com/q/908257/27535
gbn

Devi selezionare Seleziona ID, .. da Inserito, qui Scope_Identity, @@ L'identità non funzionerà

Risposte:


8

Con un trigger INSTEAD_OF significa che non si è ancora verificato alcun inserimento. Non puoi conoscere l'identità poiché non è stata ancora generata. È possibile sgattaiolare il valore dai metadati ( DBCC CHECKIDENT) ma fare affidamento su di esso non funzionerà correttamente in concorrenza e inoltre richiede privilegi elevati.

I trigger INSTEAD_OF sono estremamente rari e un odore di codice serio. Sei sicuro di averne bisogno? Non riesci a fare il lavoro con un normale trigger AFTER?


Voglio controllare l'integrità dei dati della riga inserita. prima di salvarli. Se i dati non sono buoni, sollevo un messaggio proporzionale di errore.
Mehdi Lotfi,

2
Stai descrivendo una chiave esterna. Dovrebbe essere responsabilità dell'applicazione inserire nella tabella figlio, non un trigger. Farlo da un trigger è una cattiva progettazione e in ogni caso può essere fatto da un normale trigger AFTER. Un trigger after può generare errori e causare il rollback, che è l'opzione migliore rispetto a un trigger anziché.
Remus Rusanu,

1
Che idea assurda: "invece dei trigger c'è un odore di codice serio"? Sono molto utili rispetto a un trigger successivo: in cui, se le regole aziendali vengono violate, hai svolto il lavoro due volte - hai inserito le righe e poi le hai ripristinate. Un trigger anziché trigger può impedire l'esecuzione di qualsiasi lavoro se le regole aziendali non possono essere applicate con DRI normale o altri vincoli.
Aaron Bertrand

1
Mentre "anziché i trigger sono un odore di codice serio", non è una regola rigorosa, si basa su possibili problemi reali che può causare in un sistema completo. In generale, le infrazioni alle regole aziendali non dovrebbero mai verificarsi nel sistema, per non parlare del raggiungimento del livello di database. In tal caso, una convalida della regola nel trigger è appropriata solo come ultimo meccanismo di difesa nel caso in cui vi sia un buco nel sistema.
Alireza,

4
L'integrità dichiarativa è sempre meglio di un trigger. Un trigger after è sempre meglio di un trigger anziché di un trigger. Invece dei trigger hanno un comportamento "funky" in molte situazioni, sono opachi per accedere alle ottimizzazioni del percorso in DML, fanno sì che i livelli di isolamento si comportino in modo irregolare. Invece di innescare l'urlo "Avrei dovuto essere una procedura memorizzata di accesso". E non compro affatto l'argomento "fai il lavoro due volte", l'ottimizzazione del percorso delle eccezioni non dovrebbe influenzare il design, specialmente a costo di rallentare il percorso frequente .
Remus Rusanu,

12

Nel tuo trigger anziché, puoi sicuramente ottenere il valore inserito ... ma non fino a dopo aver eseguito l'inserimento.

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

risultati:

id
----
1

Ora ripulisci:

DROP TABLE dbo.SmellThis;

Per inciso, non dovresti mai, mai, mai usare @@IDENTITYo IDENT_CURRENT()comunque. E SCOPE_IDENTITYdovrebbe essere riservato per le situazioni in cui sai che è possibile inserire solo una riga. Un malinteso comune con i trigger è che si attivano per riga, come in altre piattaforme, ma in SQL Server si attivano per operazione - quindi un inserto multi-riga utilizzando VALUES(),(),()o INSERT...SELECT- quale SCOPE_IDENTITYsi imposta sulla variabile?


Come faccio a salvare il risultato del record inserito nella tabella delle variabili da utilizzare in seguito.
Mehdi Lotfi,

@mehdi puoi definire "più tardi"? E non puoi aggiungere colonne alla variabile di tabella che ho già dichiarato sopra?
Aaron Bertrand

3
Adoro i nomi dei tuoi tavoli.
Dan Esparza,

-1

Problema principale: il framework Trigger ed Entity funzionano entrambi in un ambito diverso. Il problema è che se si genera un nuovo valore PK nel trigger, si tratta di un ambito diverso. Pertanto, questo comando restituisce zero righe e EF genererà un'eccezione.

La soluzione è aggiungere la seguente istruzione SELECT alla fine del trigger:

SELECT * FROM deleted UNION ALL
SELECT * FROM inserted;

al posto di * puoi citare tutto il nome della colonna incluso

SELECT IDENT_CURRENT(‘tablename’) AS <IdentityColumnname>
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.