Für mehrere Tabellen mit Identitätsfeldern implementieren wir ein Sicherheitsschema auf Zeilenebene mit Views und anstelle von Triggern für diese Views. Hier ist ein vereinfachtes Beispiel Struktur:SQL Server - Datensatzidentitätswert bei Verwendung eines Views statt eines Triggers erhalten
-- 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
Wenn ich einen Datensatz eingefügt werden soll und seine Identität bekommen, bevor die RLS Instead Of-Trigger Implementierung, habe ich:
DECLARE @ItemId int;
INSERT INTO tblItem (Name)
VALUES ('MyName');
SELECT @ItemId = SCOPE_IDENTITY();
Mit dem Trigger SCOPE_IDENTITY () funktioniert nicht mehr - es gibt NULL zurück. Ich habe Vorschläge für die Verwendung der OUTPUT-Klausel gesehen, um die Identität zurück zu bekommen, aber ich kann nicht scheinen, dass es so funktioniert, wie ich es brauche. Wenn ich die OUTPUT-Klausel auf den View-Insert setze, wird nichts mehr eingegeben.
-- Nothing is added to @ItemIds
DECLARE @ItemIds TABLE (ItemId int);
INSERT INTO vwItem (Name)
OUTPUT INSERTED.ItemId INTO @ItemIds
VALUES ('MyName');
Wenn ich die OUTPUT-Klausel in dem Trigger auf der INSERT-Anweisung setzte, gibt den Auslöser die Tabelle (ich es von SQL Management Studio anzeigen kann). Ich kann es anscheinend nicht im Anrufcode erfassen; entweder mit einer OUTPUT-Klausel für diesen Aufruf oder mit SELECT * FROM().
Das einzige, was ich mir vorstellen kann, ist die IDENT_CURRENT() -Funktion zu verwenden. Da dies im aktuellen Bereich nicht funktioniert, gibt es ein Problem, dass gleichzeitige Benutzer gleichzeitig einfügen und es vermasseln. Wenn die gesamte Operation in eine Transaktion eingeschlossen wird, würde dies das Problem der Parallelität verhindern?
BEGIN TRANSACTION
DECLARE @ItemId int;
INSERT INTO tblItem (Name)
VALUES ('MyName');
SELECT @ItemId = IDENT_CURRENT('tblItem');
COMMIT TRANSACTION
Hat jemand irgendwelche Vorschläge, wie man das besser macht?
Ich kenne Leute da draußen, die das lesen werden und sagen: "Trigger sind BÖSE, benutze sie nicht!" Während ich Ihre Überzeugungen schätze, bieten Sie diesen "Vorschlag" bitte nicht an.
Siehe meine ähnliche Frage zu CONTEXT_INFO() verwenden: http://stackoverflow.com/questions/1616229/contextinfo-and-convert –
@ Rob: Ich habe eine Antwort auf diese – gbn