我想了一会儿这个话题,想出了一个我以前没有见过的非常简单的解决方案,所以我想分享一下:
由于不可能重新抛出相同的错误,因此必须抛出一个很容易映射到原始错误的错误,例如通过为每个系统错误添加一个固定数字(如 100000)。
将新映射的消息添加到数据库后,可能会引发任何系统错误,固定偏移量为 100000。
这里是用于创建映射消息的代码(对于整个 SQL Server 实例,只需执行一次。在这种情况下,通过添加适当的偏移量(如 100000)来避免与其他用户定义的消息发生冲突):
DECLARE messageCursor CURSOR
READ_ONLY
FOR select
message_id + 100000 as message_id, language_id, severity, is_event_logged, [text]
from
sys.messages
where
language_id = 1033
and
message_id < 50000
and
severity > 0
DECLARE
@id int,
@severity int,
@lang int,
@msgText nvarchar(1000),
@withLog bit,
@withLogString nvarchar(100)
OPEN messageCursor
FETCH NEXT FROM messageCursor INTO @id, @lang, @severity, @withLog, @msgText
WHILE (@@fetch_status <> -1)
BEGIN
IF (@@fetch_status <> -2)
BEGIN
set @withLogString = case @withLog when 0 then 'false' else 'true' end
exec sp_addmessage @id, @severity, @msgText, 'us_english', @withLogString, 'replace'
END
FETCH NEXT FROM messageCursor INTO @id, @lang, @severity, @withLog, @msgText
END
CLOSE messageCursor
DEALLOCATE messageCursor
这是引发新创建的错误代码的代码,这些错误代码与原始代码有一个修复偏移:
SELECT
@ErrorNumber = ERROR_NUMBER(),
@ErrorSeverity = ERROR_SEVERITY(),
@ErrorState = ERROR_STATE()
set @MappedNumber = @ErrorNumber + 100000;
RAISERROR
(
@MappedNumber,
@ErrorSeverity,
1
);
有一个小警告:在这种情况下,您不能自己提供消息。但这可以通过在 sp_addmessage 调用中添加额外的 %s 或通过将所有映射的消息更改为您自己的模式并在 raiseerror 调用中提供正确的参数来规避。最好的办法是将所有消息设置为相同的模式,如 '%s (line: %d procedure: %s)%s',这样您就可以提供原始消息作为第一个参数并附加真实的过程和行以及您自己的消息作为其他参数。
在客户端中,您现在可以进行所有普通的异常处理,就像原始消息会被抛出一样,您只需要记住添加修复偏移量。您甚至可以使用相同的代码处理原始异常和重新引发的异常,如下所示:
switch(errorNumber)
{
case 8134:
case 108134:
{
}
}
所以你甚至不必知道它是重新抛出的还是原来的错误,它总是正确的,即使你忘记处理你的错误并且原来的错误漏掉了。
在其他地方提到了一些关于提出你不能提出的消息或你不能使用的状态的增强。这些被忽略在这里只显示这个想法的核心。