我有一个C#程序插入到具有标识列(id)的表中。
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!
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#..我该怎么做?
答案 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