2009-10-23 16 views
5

Para varias tablas que tienen campos de identidad, estamos implementando un esquema de seguridad de nivel de fila utilizando los disparadores Vistas y En lugar de en esas vistas. Aquí es una estructura simplificada ejemplo:Servidor SQL: obtenga el valor de identidad de registro insertado cuando utilice una vista en lugar de desencadenar

-- 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 quiero insertar un registro y obtener su identidad, antes de la aplicación de la RLS En vez de gatillo, que utiliza:

DECLARE @ItemId int; 

INSERT INTO tblItem (Name) 
VALUES ('MyName'); 

SELECT @ItemId = SCOPE_IDENTITY(); 

Con el gatillo, SCOPE_IDENTITY () ya no funciona - devuelve NULL. He visto sugerencias para usar la cláusula OUTPUT para recuperar la identidad, pero parece que no puedo hacer que funcione de la manera que lo necesito. Si pongo la cláusula OUTPUT en la inserción de vista, nunca se ingresa nada.

-- Nothing is added to @ItemIds 
DECLARE @ItemIds TABLE (ItemId int); 

INSERT INTO vwItem (Name) 
OUTPUT INSERTED.ItemId INTO @ItemIds 
VALUES ('MyName'); 

Si pongo la cláusula de salida en el gatillo de la instrucción INSERT, el gatillo devuelve la mesa (puedo verlo desde SQL Server Management Studio). Parece que no puedo capturarlo en el código de llamada; ya sea usando una cláusula OUTPUT en esa llamada o usando 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'); 

Lo único que se me ocurre es usar la función IDENT_CURRENT(). Como eso no funciona en el ámbito actual, hay un problema de usuarios concurrentes que se insertan al mismo tiempo y lo estropean. Si toda la operación está envuelta en una transacción, ¿eso evitaría el problema de concurrencia?

BEGIN TRANSACTION 

DECLARE @ItemId int; 

INSERT INTO tblItem (Name) 
VALUES ('MyName'); 

SELECT @ItemId = IDENT_CURRENT('tblItem'); 

COMMIT TRANSACTION 

¿Alguien tiene alguna sugerencia sobre cómo hacerlo mejor?

Conozco gente que leerá esto y dirá "Los desencadenantes son MALVADOS, ¡no los use!" Si bien aprecio sus convicciones, no ofrezca esa "sugerencia".

Respuesta

1

Puede probar SET CONTEXT_INFO desde el gatillo para ser leído por CONTEXT_INFO() en el cliente.

Lo usamos a la inversa para pasar información al disparador, pero funcionaría al revés.

+1

Consulte mi pregunta relacionada sobre CONTEXT_INFO() use: http://stackoverflow.com/questions/1616229/contextinfo-and-convert –

+0

@Rob: He añadido una respuesta a esta – gbn

1

¿Ha probado en este caso @@ identity? Usted mencionó tanto scope_Identity() como identity_current() pero no @@ identity.

+0

Buena idea. El "problema" de alcance habitual podría ser una ayuda en este caso. – gbn

+0

¿Cómo sería @@ IDENTITY mejor que IDENT_CURRENT()? Por lo que entiendo, aunque ninguno de los dos se limita al alcance del código de llamada, @@ IDENTIDAD es el último valor de identidad insertado, sin importar dónde. Entonces, si tengo un activador de auditoría en la tabla que inserta un registro en una tabla de auditoría, @@ IDENTIDAD podría devolver la identidad de esa fila (si entiendo correctamente). Es por eso que pensé que IDENT_CURRENT() era mejor porque al menos limitaba el "alcance" a la tabla específica. – CuppM

+0

@CuppM: @@ IDENTITY es por sesión, no por alcance. IDENT_CURRENT() no es ni puede por ninguna sesión/alcance – gbn

Cuestiones relacionadas