Tôi nghĩ về chủ đề này trong một thời gian và đã đưa ra một giải pháp rất đơn giản mà tôi không nhìn thấy trước vì vậy tôi muốn chia sẻ điều này:
Vì nó là không thể rethrow các cùng một lỗi, người ta phải ném một lỗi rất dễ dàng để ánh xạ tới lỗi ban đầu, ví dụ bằng cách thêm một số cố định như 100000 vào mọi lỗi hệ thống.
Sau những thông điệp mới được ánh xạ được bổ sung vào cơ sở dữ liệu có thể ném bất kỳ lỗi hệ thống với một cố định bù đắp của 100000.
Đây là đoạn mã để tạo các thông điệp ánh xạ (điều này đã được thực hiện chỉ có một . thời gian cho cả Instance SQL server Tránh đụng độ với những thông điệp người dùng định nghĩa khác bằng cách thêm một thích hợp bù đắp như 100000 trong trường hợp này):
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
Và đây là đoạn code để nâng cao mã lỗi mới được tạo ra có một sửa chữa bù đắp từ mã gốc:
SELECT
@ErrorNumber = ERROR_NUMBER(),
@ErrorSeverity = ERROR_SEVERITY(),
@ErrorState = ERROR_STATE()
set @MappedNumber = @ErrorNumber + 100000;
RAISERROR
(
@MappedNumber,
@ErrorSeverity,
1
);
Có một cảnh báo nhỏ: Bạn không thể tự cung cấp thư trong trường hợp này.Nhưng điều này có thể được phá vỡ bằng cách thêm một% s bổ sung trong cuộc gọi sp_addmessage hoặc bằng cách thay đổi tất cả các thư được ánh xạ thành mẫu của riêng bạn và cung cấp các tham số đúng trong lệnh gọi raiseerror. Điều tốt nhất để thiết lập tất cả các thông báo giống như '% s (dòng:% d thủ tục:% s)% s', vì vậy bạn có thể cung cấp thông điệp ban đầu làm tham số đầu tiên và nối thêm thủ tục và dòng thực và của riêng bạn thông báo như các thông số khác.
Trong ứng dụng khách, bây giờ bạn có thể thực hiện tất cả xử lý ngoại lệ thông thường như các thư gốc sẽ bị ném, bạn chỉ phải nhớ thêm bù đắp sửa lỗi. Bạn thậm chí có thể xử lý ngoại lệ ban đầu và rethrown với cùng mã như thế này:
switch(errorNumber)
{
case 8134:
case 108134:
{
}
}
Vì vậy, bạn thậm chí không cần phải biết nếu nó là một rethrown hoặc lỗi ban đầu, đó là luôn luôn đúng, ngay cả khi bạn quên xử lý lỗi của bạn và lỗi gốc bị trượt qua.
Có một số tính năng nâng cao được đề cập ở những nơi khác liên quan đến việc nâng cao các thư bạn không thể nâng cao hoặc cho biết bạn không thể sử dụng. Những người bị bỏ lại ở đây để chỉ cho thấy cốt lõi của ý tưởng.
Tôi không nghĩ rằng bạn thậm chí cần giao dịch nếu bạn chỉ muốn bắt lỗi ban đầu: chỉ cần không sử dụng TRY/CATCH hoặc RAISERROR() ở phía T-SQL. Ngoài ra, cách tiếp cận TransactionScope hoạt động tốt cho các truy vấn đơn giản hoặc SP, nhưng có các trường hợp góc với các SP phức tạp hơn, nơi nó không làm điều đúng. – RickNZ
@RickNZ, tôi quên đề cập đến trong câu hỏi rằng tôi đang sử dụng hai lệnh INSERT và đó là lý do tại sao giao dịch là cần thiết. Đóng góp tốt mặc dù! –