Per diverse tabelle con campi di identità, stiamo implementando uno schema di sicurezza a livello di riga utilizzando i trigger Viste e Anziché su tali viste. Ecco una struttura semplificata esempio:SQL Server - Ottieni valore di identità record inserito quando si utilizza una vista anziché trigger
-- 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
Se voglio inserire un record e ottenere la sua identità, prima di attuare il RLS Invece di innesco, ho usato:
DECLARE @ItemId int;
INSERT INTO tblItem (Name)
VALUES ('MyName');
SELECT @ItemId = SCOPE_IDENTITY();
Con il grilletto, SCOPE_IDENTITY () non funziona più - restituisce NULL. Ho visto suggerimenti per l'utilizzo della clausola OUTPUT per recuperare l'identità, ma non riesco a farlo funzionare nel modo in cui ne ho bisogno. Se inserisco la clausola OUTPUT nella vista insert, non viene mai inserita nulla.
-- Nothing is added to @ItemIds
DECLARE @ItemIds TABLE (ItemId int);
INSERT INTO vwItem (Name)
OUTPUT INSERTED.ItemId INTO @ItemIds
VALUES ('MyName');
Se metto la clausola OUTPUT nel trigger sulla istruzione INSERT, il trigger restituisce il tavolo (posso vederlo da SQL Management Studio). Non riesco a catturarlo nel codice chiamante; o utilizzando una clausola OUTPUT su quella chiamata o utilizzando 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');
L'unica cosa che posso pensare è utilizzare la funzione IDENT_CURRENT(). Dal momento che ciò non funziona nell'ambito attuale, c'è un problema di utenti simultanei che inseriscono allo stesso tempo e lo incasinano. Se l'intera operazione è racchiusa in una transazione, ciò impedirebbe il problema di concorrenza?
BEGIN TRANSACTION
DECLARE @ItemId int;
INSERT INTO tblItem (Name)
VALUES ('MyName');
SELECT @ItemId = IDENT_CURRENT('tblItem');
COMMIT TRANSACTION
Qualcuno ha qualche suggerimento su come farlo meglio?
Conosco persone che leggeranno e dicono "I trigger sono MALE, non usarli!" Mentre apprezzo le tue convinzioni, per favore non offrire quel "suggerimento".
Vedi il mio quesito, circa CONTEXT_INFO() utilizzare: http://stackoverflow.com/questions/1616229/contextinfo-and-convert –
@ Rob: Ho aggiunto una risposta a questa – gbn