无法获得插入行的标识。触发器返回结果集,服务器选项不允许触发器的结果'是真的

时间:2018-03-21 11:43:53

标签: c# sql-server triggers

我有一个C#程序插入到具有标识列(id)的表中。

C#代码

String sql = "insert into my_table (col_a,col_b) values (@val_a,@val_b); select @@identity;";
SqlCommand cmd = new SqlCommand(sql,conn);
... 
... // parameters code
...
Int inserted_id =  cmd.ExecuteScalar();   // Exception!

SQL触发器

CREATE TRIGGER [dbo].[trg_my_trigger] ON [dbo].[my_table]
WITH EXEC AS CALLER
AFTER INSERT
AS
begin
  declare @row_id int;

  select @row_id = id from inserted;

  insert into log_table(remarks1,remarks2) values ('new row inserted',@row_id);


end
GO

代码工作正常,但触发器导致@@identity成为log_table insert语句的代码。

所以我在触发器的底部添加了这一行:

begin
  declare @row_id int;

  select @row_id = id from inserted;

  insert into log_table(remarks1,remarks2) values ('new row inserted',@row_id);

 select @row_id;   -- this is causing the error

end
GO

现在触发器引发错误:

  

触发器返回结果集,服务器选项“禁止触发器的结果”。是的。

我没有权限修改服务器变量。 我想要的只是将触发器插入到日志中,然后将插入的id返回给c#..我该怎么做?

1 个答案:

答案 0 :(得分:3)

@@identity已知存在缺陷,因为它会根据您在会话中执行的最后一次插入提供答案。

如果您按照大多数人的建议切换到scope_identity,它将解决问题而无需更改触发器 - 因为触发器定义了自己的范围。

  

例如,有两个表,T1和T2,并且在T1上定义了INSERT触发器。当一行插入T1时,触发器将触发并在T2中插入一行。此方案说明了两个范围:T1上的插入和触发器上T2的插入。

     

假设T1和T2都有标识列,@@ IDENTITY和SCOPE_IDENTITY在T1上的INSERT语句末尾返回不同的值。 @@ IDENTITY返回在当前会话中的任何范围内插入的最后一个标识列值。 [...] SCOPE_IDENTITY()返回在T1中插入的​​IDENTITY值。

另外,请注意您当前的触发器已被破坏 - 它假定inserted正好包含1行,而实际上它可能包含0,1或多个行。你应该改为:

CREATE TRIGGER [dbo].[trg_my_trigger] ON [dbo].[my_table]
WITH EXEC AS CALLER
AFTER INSERT
AS
begin
  insert into log_table(remarks1,remarks2)
  select 'new row inserted',id
  from inserted
end
GO