W przypadku kilku tabel z polami tożsamości wdrażamy schemat zabezpieczeń poziomu wiersza z widokami i zamiast wyzwalaczy dla tych widoków. Oto uproszczony przykład struktura:Serwer SQL - Uzyskaj wstawioną wartość tożsamości rekordu podczas korzystania z widoku zamiast wyzwalacza
-- 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
Jeśli chcę wstawić rekord i dostać swoją tożsamość, przed wdrożeniem RLS zamiast spustu, użyłem:
DECLARE @ItemId int;
INSERT INTO tblItem (Name)
VALUES ('MyName');
SELECT @ItemId = SCOPE_IDENTITY();
Przy spuście, SCOPE_IDENTITY () już nie działa - zwraca NULL. Widziałem sugestie użycia klauzuli OUTPUT, aby odzyskać tożsamość, ale nie mogę sprawić, by działała tak, jak tego potrzebuję. Jeśli wstawię klauzulę OUTPUT do wstawki widoku, nic nigdy nie zostanie do niej wprowadzone.
-- Nothing is added to @ItemIds
DECLARE @ItemIds TABLE (ItemId int);
INSERT INTO vwItem (Name)
OUTPUT INSERTED.ItemId INTO @ItemIds
VALUES ('MyName');
Jeśli mogę umieścić klauzulę wyjście w wyzwalacz na INSERT, spust zwraca tabelę (mogę go zobaczyć z SQL Management Studio). Nie mogę uchwycić tego w kodzie wywołującym; poprzez użycie klauzuli OUTPUT dla tego połączenia lub użycie 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');
Jedyne, co mogę myśleć, to użyć funkcji IDENT_CURRENT(). Ponieważ nie działa w bieżącym zakresie, pojawia się problem równoczesnego wstawiania użytkowników i zmyślania. Jeśli cała operacja jest zawijana w transakcji, czy to zapobiegnie problemowi współbieżności?
BEGIN TRANSACTION
DECLARE @ItemId int;
INSERT INTO tblItem (Name)
VALUES ('MyName');
SELECT @ItemId = IDENT_CURRENT('tblItem');
COMMIT TRANSACTION
Czy ktoś ma jakieś sugestie, jak to zrobić lepiej?
Znam ludzi, którzy to przeczytają i powiedzą: "Wyzwalacze to ZŁY, nie używajcie ich!" Doceniamy twoje przekonania, ale nie proponuj tej "sugestii".
Zobacz moją powiązane pytanie o CONTEXT_INFO() użyć: http://stackoverflow.com/questions/1616229/contextinfo-and-convert –
@Rob: dodałem odpowiedź do tej – gbn