我想過這個話題了一會兒,用一個非常簡單的解決方案,我沒有看到過上來,所以我想分享這個:
因爲它是不可能重新拋出同樣的錯誤,人們必須拋出一個很容易映射到原始錯誤的錯誤,例如通過爲每個系統錯誤添加一個固定的數字,例如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:
{
}
}
所以你甚至不必知道它是一個重新拋出還是原來的錯誤,它總是正確的,即使你忘了處理您的錯誤,並且原始錯誤通過。
在其他地方提到了一些有關提升您無法提出或聲明不能使用的消息的增強功能。那些被遺漏在這裏僅僅展示了這個想法的核心。
我不認爲你甚至需要事務,如果你只是想捕獲原始錯誤:只是不要在T-SQL端使用TRY/CATCH或RAISERROR()。此外,TransactionScope方法對於簡單查詢或SP來說工作得很好,但是有些情況下更復雜的SP不適合做正確的事情。 – RickNZ 2009-12-11 13:53:06
@RickNZ,我忘了在提問中提到我使用了兩條INSERT指令,這就是爲什麼需要這個事務。雖然貢獻良多! – 2009-12-12 16:28:43