Cuando inserto en tablas usando en lugar de disparadores @@Identity
, IDENT_CURRENT('Table')
y SCOPE_IDENTITY()
devuelvo nulo. ¿Cómo puedo obtener la última identidad de la fila insertada?
Cuando inserto en tablas usando en lugar de disparadores @@Identity
, IDENT_CURRENT('Table')
y SCOPE_IDENTITY()
devuelvo nulo. ¿Cómo puedo obtener la última identidad de la fila insertada?
Respuestas:
Con un desencadenador INSTEAD_OF significa que aún no se ha insertado. No puede conocer la identidad ya que aún no se generó. Es posible escabullir el valor de los metadatos ( DBCC CHECKIDENT
), pero confiar en él no funcionará correctamente bajo concurrencia y además requiere privilegios elevados.
Los desencadenadores INSTEAD_OF rara vez se requieren y un olor a código serio. ¿Estás seguro de que lo necesitas? ¿No puedes hacer el trabajo con un disparador DESPUÉS regular?
En su activador en lugar de en el disparador, definitivamente puede obtener el valor insertado ... pero no hasta después de haber realizado la inserción.
USE tempdb;
GO
CREATE TABLE dbo.SmellThis
(
id INT IDENTITY(1,1),
name VARCHAR(32)
);
GO
CREATE TRIGGER dbo.SmellThis_First
ON dbo.SmellThis
INSTEAD OF INSERT
AS
BEGIN
SET NOCOUNT ON;
DECLARE @ids TABLE(id INT);
IF NOT EXISTS
(
SELECT 1 FROM sys.objects AS o
INNER JOIN inserted AS i
ON o.name = i.name
)
INSERT dbo.SmellThis(name)
OUTPUT inserted.id INTO @ids
SELECT name
FROM inserted;
SELECT id FROM @ids;
END
GO
INSERT dbo.SmellThis(name) SELECT 'Remus';
GO
Resultados:
id
----
1
Ahora limpia:
DROP TABLE dbo.SmellThis;
Por otro lado, nunca, nunca, nunca deberías estar usando @@IDENTITY
o de IDENT_CURRENT()
todos modos. Y SCOPE_IDENTITY
debe reservarse para situaciones en las que sabe que solo se puede insertar una fila. Una idea errónea común con los desencadenantes es que se disparan por fila, como en otras plataformas, pero en SQL Server se disparan por operación, por lo que una inserción de varias filas usando VALUES(),(),()
o INSERT...SELECT
, SCOPE_IDENTITY
¿qué establecería en su variable?
Problema principal: el marco de activación y entidad funciona en un alcance diferente. El problema es que si genera un nuevo valor de PK en el disparador, el alcance es diferente. Por lo tanto, este comando devuelve cero filas y EF arrojará una excepción.
La solución es agregar la siguiente instrucción SELECT al final de su Trigger:
SELECT * FROM deleted UNION ALL
SELECT * FROM inserted;
en lugar de * puede mencionar todo el nombre de la columna, incluido
SELECT IDENT_CURRENT(‘tablename’) AS <IdentityColumnname>
inserted
ninguna fila insertada cuando seINSTEAD OF
activa un disparador.