Как получить последнюю строку идентификатора, вставленную при использовании вместо триггера


9

Когда я вставляю в таблицы, используя вместо триггеров @@Identity, IDENT_CURRENT('Table')и SCOPE_IDENTITY()возвращаю ноль. Как я могу получить последний идентификатор вставленной строки?


Существует , insertedно ни одна строка не вставлена , когда INSTEAD OFтриггер триггерами.
— ypercubeᵀᴹ

Проверьте этот ТАК вопрос: это может помочь. stackoverflow.com/q/908257/27535
— 2012 г.

Вы должны выбрать Select Id, .. из Inserted, здесь Scope_Identity, @@ Identity не будет работать

Ответы:


8

С триггером INSTEAD_OF это означает, что вставка еще не произошла. Вы не можете знать личность, так как она еще не была создана. Возможно получить значение из метаданных ( DBCC CHECKIDENT), но полагаться на него не будет правильно при параллельном выполнении, и, кроме того, оно требует повышенных привилегий.

Триггеры INSTEAD_OF крайне редко требуются и имеют серьезный запах кода. Вы уверены, что вам это нужно? Разве вы не можете работать с обычным триггером ПОСЛЕ?


Я хочу контролировать целостность данных вставленной строки. прежде чем сохранить их. Если данные не хорошие, я выдаю сообщение об ошибке пропорционально.
— Мехди Лотфи

2
Вы описываете внешний ключ. Приложение должно нести ответственность за вставку в дочернюю таблицу, а не за триггер. Выполнение этого из триггера - плохой дизайн, и в любом случае это может быть сделано из обычного ПОСЛЕ триггера. Триггер после может вызвать ошибки и вызвать откат, который является лучшим вариантом, чем триггер вместо.
— Ремус Русану

1
Что за абсурдное понятие - «вместо триггеров есть серьезный запах кода»? Они очень полезны по сравнению с триггером после - где, если ваши бизнес-правила нарушены, вы проделали работу дважды - вы вставили строки и затем откатили их назад. Триггер вместо может предотвратить любую работу, если ваши бизнес-правила не могут быть реализованы с помощью нормального DRI или других ограничений.
— Аарон Бертран

1
Хотя «триггеры не являются серьезным запахом кода», это не является строгим правилом, оно основано на реальных возможных проблемах, которые могут возникнуть в полной системе. В общем, нарушители бизнес-правил никогда не должны происходить в системе, не говоря уже о достижении уровня базы данных. В этом случае валидация правила в триггере подходит только в качестве последнего защитного механизма, если в системе есть дыра.
— Алиреза

4
Декларативная целостность всегда лучше, чем триггер. Триггер после всегда лучше, чем триггер вместо. Вместо этого триггеры во многих ситуациях ведут себя как «фанки», они непрозрачны для доступа к оптимизации пути в DML, они делают уровни изоляции неправильными. Вместо триггеров выкрикивают: «Я должен был вместо этого использовать хранимую процедуру доступа». И я вообще не покупаю аргумент «делай работу дважды», оптимизация пути исключения не должна влиять на дизайн, особенно за счет замедления частого пути.
— Ремус Русану

12

Вместо триггера вы определенно можете получить вставленное значение ... но только после того, как вы выполните вставку.

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бы вы указали для своей переменной?


Как сохранить результат вставленной записи в таблицу переменных для последующего использования.
— Мехди Лотфи

@ mehdi вы можете определить "позже"? И вы не можете добавить столбцы к табличной переменной, которую я уже объявил выше?
— Аарон Бертран

3
Я люблю твои имена столов.
— Дэн Эспарза,

-1

Основная проблема: Trigger и Entity Framework работают в разных сферах. Проблема в том, что если вы генерируете новое значение PK в триггере, это будет другой областью действия. Таким образом, эта команда возвращает ноль строк и EF сгенерирует исключение.

Решение состоит в том, чтобы добавить следующий оператор SELECT в конце вашего триггера:

SELECT * FROM deleted UNION ALL
SELECT * FROM inserted;

вместо * вы можете указать все названия столбцов, включая

SELECT IDENT_CURRENT(‘tablename’) AS <IdentityColumnname>
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.