Lorsque j'insère dans des tables en utilisant au lieu de déclencheurs @@Identity
, IDENT_CURRENT('Table')
et SCOPE_IDENTITY()
retourne null. Comment puis-je obtenir la dernière identité de la ligne insérée?
Lorsque j'insère dans des tables en utilisant au lieu de déclencheurs @@Identity
, IDENT_CURRENT('Table')
et SCOPE_IDENTITY()
retourne null. Comment puis-je obtenir la dernière identité de la ligne insérée?
Réponses:
Avec un déclencheur INSTEAD_OF, cela signifie qu'aucune insertion n'a encore eu lieu. Vous ne pouvez pas connaître l'identité car elle n'a pas encore été générée. Il est possible d'extraire la valeur des métadonnées ( DBCC CHECKIDENT
), mais s'appuyer dessus ne fonctionnera pas correctement dans le cadre de la concurrence et, en outre, cela nécessite des privilèges élevés.
Les déclencheurs INSTEAD_OF sont extrêmement rarement requis et une odeur de code sérieuse. Êtes-vous sûr d'en avoir besoin? Vous ne pouvez pas faire le travail avec un déclencheur AFTER régulier?
Dans votre lieu de déclencheur, vous pouvez certainement obtenir la valeur insérée ... mais pas avant d'avoir effectué l'insertion.
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
Résultats:
id
----
1
Maintenant nettoyez:
DROP TABLE dbo.SmellThis;
En passant, vous ne devriez jamais, jamais, jamais utiliser @@IDENTITY
ou de IDENT_CURRENT()
toute façon. Et SCOPE_IDENTITY
devrait être réservé aux situations où vous savez qu'une seule ligne peut être insérée. Une idée fausse commune avec les déclencheurs est qu'ils se déclenchent par ligne, comme dans d'autres plates-formes, mais dans SQL Server, ils se déclenchent par opération - donc une insertion à plusieurs lignes en utilisant VALUES(),(),()
ou INSERT...SELECT
- que SCOPE_IDENTITY
définiriez-vous pour votre variable?
Problème principal: Trigger et Entity Framework fonctionnent tous les deux dans une portée différente. Le problème est que si vous générez une nouvelle valeur PK dans le déclencheur, la portée est différente. Ainsi, cette commande ne renvoie aucune ligne et EF lève une exception.
La solution consiste à ajouter l'instruction SELECT suivante à la fin de votre déclencheur:
SELECT * FROM deleted UNION ALL
SELECT * FROM inserted;
au lieu de *, vous pouvez mentionner tout le nom de la colonne, y compris
SELECT IDENT_CURRENT(‘tablename’) AS <IdentityColumnname>
inserted
pas de ligne insérée lorsqu'unINSTEAD OF
déclencheur se déclenche.