[英]How do I catch a SqlException thrown by RAISERROR called in a trigger set off by Entity Framework 4?
[英]Commit and Raiserror in a trigger
也许有更好的方法可以做到这一点。 我想要的目的是让SQL Server向我提出两种类型的错误:更新表时,警告和来自触发器的错误。 如果SQL Server返回警告,则触发器应提交但向用户显示警告(使用.NET-优选通过SQL Exception,仅在严重性> 10时才会引发),并且如果它是ERROR,则触发器应回滚并显示ERROR给用户(通过SQL异常)。 我对此的尝试(不必说这是行不通的)是这样的触发器:
ALTER TRIGGER [dbo].[TR_TRANSACTION_UPDATE]
ON [dbo].[tTRANSACTION]
FOR UPDATE
AS
BEGIN
...
BEGIN TRY
DECLARE @id INT ,@maxid INT
SELECT @id = 0 ,@maxid = MAX(transID) FROM INSERTED
WHILE @id < @maxid
BEGIN
SELECT @id = MIN([TransID]) FROM INSERTED WHERE [TransID] > @id
EXEC dbo.sp_CheckTransaction @TransID = @id
END
COMMIT TRANSACTION
END TRY
BEGIN CATCH
DECLARE @err_msg VARCHAR(MAX), @err_sev AS INT, @err_state AS INT
SELECT @err_msg = ERROR_MESSAGE(), @err_sev = ERROR_SEVERITY(), @err_state = ERROR_STATE()
IF @err_state <> 120 -- '120 is not a fatal error from STORED_PROC
ROLLBACK TRANSACTION
ELSE
COMMIT TRANSACTION
RAISERROR(@err_msg, @err_sev, @err_state)
END CATCH
END
此触发器不起作用,因为它认为事务不可提交。
另外,sp_CheckTransaction可以引发2种类型的错误:
RAISERROR(@msg, 15, 120) -- warning
or RAISERROR(@msg, 15, 121) -- error
我不能使用严重性<15的原因是因为我希望在.NET中显示警告(如果是警告或错误,我可以根据状态和严重性进行决定)。 .NET SqlException仅在严重性> 10时引发。
RAISERROR(@err_msg, @err_sev, @err_state)
你不可以做这个。 不允许引发系统消息,只能引发用户消息(错误号大于50000)。 您必须像这样加注:
RAISERROR(N'An error occured in trigger: %s %d %d',
<severity>, <state>, @err_msg, @err_sev, @err_state);
[ 更新:实际上因为@err_msg
是消息,而不是错误号,所以您的用法还可以,所以忽略此 ]
有关此主题的详细讨论,请参见异常处理和嵌套事务 。 您将在此处看到解释了为什么您的实现存在缺陷的原因(它不应该检查XACT_STATE()),并且链接的文章提供了更好的实现。
现在回到您的痛点:您需要了解SQL Server错误严重性模型。 严重性高于10时引发的错误是错误,并且ADO.Net将为其引发异常。 严重性低于10引发的错误是参考消息,ADO.NEt将为其引发SqlConnection.InfoMessage
事件。 另请参见不同的RAISERROR严重性级别是什么意思?
因此,问题的真正根源不是触发器,而是sp_CheckTransaction
存储过程。 对于错误,它应该提高严重性16,对于警告应该提高严重性0:
RAISERROR(@msg, 0, 120) -- warning
要么
RAISERROR(@msg, 16, 121) -- error
并使用SqlConnection.InfoMessage
拦截警告。 尝试将状态用作严重性将使您无处快速。
您的触发器可能会捕获并重新抛出该错误,具体取决于许多因素,但是您极不可能需要。 如果确实捕获到异常,则需要引发一个新的错误,并且需要适当的逻辑来处理严重性(针对错误提高16,对于警告提高0)。 请勿在T-SQL代码中使用16和0以外的其他严重性。
附带说明,从下一版本的SQL Server开始,您将能够使用简单的THROW;
重新引发原始异常,就像在.Net异常处理中一样。 更多信息SQL Server v.Next(Denali):探索THROW 。
我建议不要使用这种设计。 这使您难以测试代码,但是如果由于某种原因而以这种方式坚持执行此操作,请按以下步骤操作。
raiserror('foo',1,1)将引发一个错误,但不会导致触发器的执行停止。 如果严重性大于10,我相信它会将事务回滚。
http://msdn.microsoft.com/en-us/library/ms177497.aspx
然后,您必须使用SqlConnection来显示错误消息。
你有没有尝试过:
IF @err_state <> 120 -- '120 is not a fatal error from STORED_PROC'
代替
IF @err_state <> 120 -- '120 is not a fatal error from STORED_PROC
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.