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


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.