Pour plusieurs tables ayant des champs d'identité, nous implémentons un schéma de sécurité au niveau de la ligne utilisant les déclenchements Views et Instead de ces vues. Voici une structure exemple simplifié:SQL Server - Obtenir une valeur d'identité insérée lors de l'utilisation d'une vue à la place du déclencheur
-- Table
CREATE TABLE tblItem (
ItemId int identity(1,1) primary key,
Name varchar(20)
)
go
-- View
CREATE VIEW vwItem
AS
SELECT *
FROM tblItem
-- RLS Filtering Condition
go
-- Instead Of Insert Trigger
CREATE TRIGGER IO_vwItem_Insert ON vwItem
INSTEAD OF INSERT
AS BEGIN
-- RLS Security Checks on inserted Table
-- Insert Records Into Table
INSERT INTO tblItem (Name)
SELECT Name
FROM inserted;
END
go
Si je veux insérer un enregistrement et obtenir son identité, avant la mise en œuvre du SJSR au lieu de détente, j'ai utilisé:
DECLARE @ItemId int;
INSERT INTO tblItem (Name)
VALUES ('MyName');
SELECT @ItemId = SCOPE_IDENTITY();
Avec la gâchette, SCOPE_IDENTITY () ne fonctionne plus - il retourne NULL. J'ai vu des suggestions pour utiliser la clause OUTPUT pour récupérer l'identité, mais je n'arrive pas à la faire fonctionner comme j'en ai besoin. Si je mets la clause OUTPUT sur la vue insert, rien n'y est jamais entré.
-- Nothing is added to @ItemIds
DECLARE @ItemIds TABLE (ItemId int);
INSERT INTO vwItem (Name)
OUTPUT INSERTED.ItemId INTO @ItemIds
VALUES ('MyName');
Si je mets la clause OUTPUT dans le déclencheur sur l'instruction INSERT, le déclencheur retourne la table (je peux voir de SQL Management Studio). Je n'arrive pas à le capturer dans le code appelant; soit en utilisant une clause OUTPUT sur cet appel ou en utilisant un SELECT * FROM().
-- Modified Instead Of Insert Trigger w/ Output
CREATE TRIGGER IO_vwItem_Insert ON vwItem
INSTEAD OF INSERT
AS BEGIN
-- RLS Security Checks on inserted Table
-- Insert Records Into Table
INSERT INTO tblItem (Name)
OUTPUT INSERTED.ItemId
SELECT Name
FROM inserted;
END
go
-- Calling Code
INSERT INTO vwItem (Name)
VALUES ('MyName');
La seule chose que je peux penser est d'utiliser la fonction IDENT_CURRENT(). Comme cela ne fonctionne pas dans la portée actuelle, il y a un problème d'insertion simultanée d'utilisateurs et de confusion. Si l'opération entière est enveloppée dans une transaction, cela empêcherait-il le problème de simultanéité?
BEGIN TRANSACTION
DECLARE @ItemId int;
INSERT INTO tblItem (Name)
VALUES ('MyName');
SELECT @ItemId = IDENT_CURRENT('tblItem');
COMMIT TRANSACTION
Quelqu'un at-il des suggestions sur la façon de faire mieux?
Je connais des gens qui liront ceci et diront "Les déclencheurs sont MAUVAIS, ne les utilisez pas!" Bien que j'apprécie vos convictions, n'offrez pas cette "suggestion".
Voir ma question connexe sur CONTEXT_INFO() utiliser: http://stackoverflow.com/questions/1616229/contextinfo-and-convert –
@Rob: J'ai ajouté une réponse – gbn