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(),(),()or INSERT...SELECT-SCOPE_IDENTITY您将设置哪个变量?
在您的而不是触发器中,您绝对可以获得插入的值......但直到您执行插入之后。
结果:
现在清理:
顺便说一句,您永远不应该使用
@@IDENTITY
或IDENT_CURRENT()
无论如何。并且SCOPE_IDENTITY
应该保留用于您知道只能插入一行的情况。对触发器的一个常见误解是它们按行触发,就像在其他平台中一样,但在 SQL Server 中,它们按操作触发 - 所以多行插入使用VALUES(),(),()
orINSERT...SELECT
-SCOPE_IDENTITY
您将设置哪个变量?使用 INSTEAD_OF 触发器意味着尚未发生插入。您无法知道身份,因为它尚未生成。
DBCC CHECKIDENT
从元数据中偷取值是可能的(INSTEAD_OF 触发器极少需要,而且代码味道很重。你确定你需要它吗?您不能使用常规的 AFTER 触发器来完成这项工作吗?
主要问题:触发器和实体框架都在不同的范围内工作。问题是,如果您在触发器中生成新的 PK 值,则范围不同。因此,此命令返回零行,EF 将抛出异常。
解决方案是在触发器末尾添加以下 SELECT 语句:
代替 * 您可以提及所有列名,包括