Я хочу повторно вызвать то же исключение в SQL Server, которое только что произошло в моем блоке try. Я могу отправить такое же сообщение, но хочу выдать ту же ошибку.
BEGIN TRANSACTION
BEGIN TRY
INSERT INTO Tags.tblDomain (DomainName, SubDomainId, DomainCode, Description)
VALUES(@DomainName, @SubDomainId, @DomainCode, @Description)
COMMIT TRANSACTION
END TRY
BEGIN CATCH
declare @severity int;
declare @state int;
select @severity=error_severity(), @state=error_state();
RAISERROR(@@Error,@ErrorSeverity,@state);
ROLLBACK TRANSACTION
END CATCH
RAISERROR(@@Error, @ErrorSeverity, @state);
В этой строке будет отображаться ошибка, но мне нужна такая функциональность. Это вызывает ошибку с номером ошибки 50000, но я хочу, чтобы был выдан номер ошибки, которую я передаю @@error
,
Я хочу зафиксировать эту ошибку на интерфейсе пользователя.
т.е.
catch (SqlException ex)
{
if ex.number==2627
MessageBox.show("Duplicate value cannot be inserted");
}
Я хочу эту функциональность. чего нельзя достичь с помощью raiseerror
. Я не хочу отображать пользовательское сообщение об ошибке в конце.
RAISEERROR
должен возвращать указанную ниже ошибку, когда я передаю ErrorNo, чтобы его бросили в catch
Msg 2627, Level 14, State 1, Procedure spOTest_DomainInsert,
Строка 14 Нарушение ограничения UNIQUE KEY 'UK_DomainCode'. Невозможно вставить повторяющийся ключ в объект Tags.tblDomain. Заявление было прекращено.
РЕДАКТИРОВАТЬ:
В чем может быть недостаток неиспользования блока try catch, если я хочу, чтобы исключение обрабатывалось во внешнем интерфейсе, учитывая, что хранимая процедура содержит несколько запросов, которые необходимо выполнить?
raiserror
, что отличается от того, как C # завершает работу послеthrow
. Поэтому я добавилreturn
внутри,catch
потому что хотел соответствовать этому поведению.RAISERROR()
документы . Уровень серьезности ≥11 переходит кCATCH
блоку, только если он находится внутриTRY
блока. Итак, вы должны иметьBEGIN TRY…END CATCH
код, если хотите,RAISERROR()
чтобы он влиял на управление потоком.SQL 2012 вводит оператор throw:
http://msdn.microsoft.com/en-us/library/ee677615.aspx
BEGIN TRY BEGIN TRANSACTION ... COMMIT TRANSACTION END TRY BEGIN CATCH ROLLBACK TRANSACTION; THROW END CATCH
источник
ROLLBACK
строке важна! Без него вы можете получитьSQLException: Cannot roll back THROW
.Повторное отображение внутри блока CATCH (код до SQL2012, используйте оператор THROW для SQL2012 и более поздних версий):
DECLARE @ErrorMessage nvarchar(4000) = ERROR_MESSAGE(), @ErrorNumber int = ERROR_NUMBER(), @ErrorSeverity int = ERROR_SEVERITY(), @ErrorState int = ERROR_STATE(), @ErrorLine int = ERROR_LINE(), @ErrorProcedure nvarchar(200) = ISNULL(ERROR_PROCEDURE(), '-'); SELECT @ErrorMessage = N'Error %d, Level %d, State %d, Procedure %s, Line %d, ' + 'Message: ' + @ErrorMessage; RAISERROR (@ErrorMessage, @ErrorSeverity, 1, @ErrorNumber, @ErrorSeverity, @ErrorState, @ErrorProcedure, @ErrorLine)
источник
Я думаю, ваш выбор:
В какой-то момент SQL, вероятно, представит команду reraise или возможность отлавливать только определенные ошибки. Но пока воспользуйтесь обходным путем. Сожалею.
источник
Вы не можете: только движок может выдавать ошибки меньше 50000. Все, что вы можете сделать, это создать исключение, которое выглядит так ...
Смотрите мой ответ здесь, пожалуйста
Здесь спрашивающий использовал транзакции на стороне клиента, чтобы делать то, что он хотел, что, на мой взгляд, немного глупо ...
источник
Хорошо, это обходной путь ... :-)
DECLARE @Error_Number INT BEGIN TRANSACTION BEGIN TRY INSERT INTO Test(Id, Name) VALUES (newID(),'Ashish') /* Column 'Name' has unique constraint on it*/ END TRY BEGIN CATCH SELECT ERROR_NUMBER() --RAISERROR (@ErrorMessage,@Severity,@State) ROLLBACK TRAN END CATCH
Если вы заметили блок catch, он не вызывает ошибку, а возвращает фактический номер ошибки (а также откатывает транзакцию). Теперь в вашем .NET-коде вместо того, чтобы перехватывать исключение, если вы используете ExecuteScalar (), вы получаете фактический номер ошибки, который хотите, и соответствующий номер.
Надеюсь это поможет,
РЕДАКТИРОВАТЬ: - Просто примечание: если вы хотите получить количество затронутых записей и пытаетесь использовать ExecuteNonQuery, вышеуказанное решение может не сработать для вас. В противном случае, думаю, подойдет то, что вам нужно. Дайте мне знать.
источник
Чтобы остановить выполнение хранимой процедуры после того, как произошла ошибка, и передать ошибку обратно вызывающей программе, нужно следовать каждому оператору, который может вызвать ошибку, с помощью этого кода:
Я сам был удивлен, узнав, что выполнение хранимой процедуры может продолжаться после ошибки - не осознавая, что это может привести к некоторым трудно обнаруживаемым ошибкам.
Этот тип обработки ошибок параллелен (до .Net) Visual Basic 6. С нетерпением жду команды Throw в SQL Server 2012.
источник
Учитывая, что вы еще не перешли в 2012 год, один из способов реализовать всплытие исходного кода ошибки - использовать часть текстового сообщения исключения, которое вы (повторно) выбрасываете из блока catch. Помните, что он может содержать некоторую структуру, например текст XML для кода вызывающего абонента, который будет анализироваться в его блоке catch.
источник
Вы также можете создать хранимую процедуру-оболочку для этих сценариев, если хотите, чтобы оператор SQL выполнялся в транзакции и передавал ошибку в ваш код.
CREATE PROCEDURE usp_Execute_SQL_Within_Transaction ( @SQL nvarchar(max) ) AS SET NOCOUNT ON BEGIN TRY BEGIN TRANSACTION EXEC(@SQL) COMMIT TRANSACTION END TRY BEGIN CATCH DECLARE @ErrorMessage nvarchar(max), @ErrorSeverity int, @ErrorState int SELECT @ErrorMessage = N'Error Number: ' + CONVERT(nvarchar(5), ERROR_NUMBER()) + N'. ' + ERROR_MESSAGE() + ' Line ' + CONVERT(nvarchar(5), ERROR_LINE()), @ErrorSeverity = ERROR_SEVERITY(), @ErrorState = ERROR_STATE() ROLLBACK TRANSACTION RAISERROR (@ErrorMessage, @ErrorSeverity, @ErrorState) END CATCH GO -- Test it EXEC usp_Execute_SQL_Within_Transaction @SQL = 'SELECT 1; SELECT 2' EXEC usp_Execute_SQL_Within_Transaction @SQL = 'SELECT 1/0; SELECT 2' EXEC usp_Execute_SQL_Within_Transaction @SQL = 'EXEC usp_Another_SP'
источник
С точки зрения дизайна, какой смысл генерировать исключения с исходными номерами ошибок и настраиваемыми сообщениями? В некоторой степени это нарушает интерфейсный контракт между приложениями и базой данных. Если вы хотите перехватывать исходные ошибки и обрабатывать их в коде более высокого уровня, не обрабатывайте их в базе данных. Затем, когда вы поймаете исключение, вы можете изменить сообщение, представленное пользователю, на все, что захотите. Я бы не стал этого делать, потому что это делает код вашей базы данных «неправильным». Как говорили другие, вы должны определить набор собственных кодов ошибок (выше 50000) и вместо этого выбросить их. Затем вы можете обрабатывать проблемы целостности («Повторяющиеся значения не допускаются») отдельно от потенциальных бизнес-проблем - «Недопустимый почтовый индекс», «Не найдено строк, соответствующих критериям» и т. Д.
источник
try { code(); } catch (Exception exc) { log(exc); throw; } finally { cleanup(); }
, гдеthrow;
просто вызовет исходное исключение с его исходным контекстом.