Когда я вставляю в таблицы, используя вместо триггеров @@Identity
, IDENT_CURRENT('Table')
и SCOPE_IDENTITY()
возвращаю ноль. Как я могу получить последний идентификатор вставленной строки?
Когда я вставляю в таблицы, используя вместо триггеров @@Identity
, IDENT_CURRENT('Table')
и SCOPE_IDENTITY()
возвращаю ноль. Как я могу получить последний идентификатор вставленной строки?
Ответы:
С триггером INSTEAD_OF это означает, что вставка еще не произошла. Вы не можете знать личность, так как она еще не была создана. Возможно получить значение из метаданных ( DBCC CHECKIDENT
), но полагаться на него не будет правильно при параллельном выполнении, и, кроме того, оно требует повышенных привилегий.
Триггеры INSTEAD_OF крайне редко требуются и имеют серьезный запах кода. Вы уверены, что вам это нужно? Разве вы не можете работать с обычным триггером ПОСЛЕ?
Вместо триггера вы определенно можете получить вставленное значение ... но только после того, как вы выполните вставку.
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
Результаты:
id
----
1
Теперь убери
DROP TABLE dbo.SmellThis;
Кроме того, вы никогда, никогда, никогда не должны использовать @@IDENTITY
или в IDENT_CURRENT()
любом случае. И SCOPE_IDENTITY
должно быть зарезервировано для ситуаций, когда вы знаете, что может быть вставлена только одна строка. Распространенное заблуждение в отношении триггеров заключается в том, что они запускаются для каждой строки, как и на других платформах, но в SQL Server они запускаются для каждой операции - поэтому многострочная вставка с использованием VALUES(),(),()
или INSERT...SELECT
- что SCOPE_IDENTITY
бы вы указали для своей переменной?
Основная проблема: Trigger и Entity Framework работают в разных сферах. Проблема в том, что если вы генерируете новое значение PK в триггере, это будет другой областью действия. Таким образом, эта команда возвращает ноль строк и EF сгенерирует исключение.
Решение состоит в том, чтобы добавить следующий оператор SELECT в конце вашего триггера:
SELECT * FROM deleted UNION ALL
SELECT * FROM inserted;
вместо * вы можете указать все названия столбцов, включая
SELECT IDENT_CURRENT(‘tablename’) AS <IdentityColumnname>
inserted
но ни одна строка не вставлена , когдаINSTEAD OF
триггер триггерами.