Как восстановить одно и то же исключение в sql-сервере
Я хочу восстановить одно и то же исключение в sql-сервере, которое произошло в моем блоке 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, но я хочу, чтобы число erron было выбрано, что я прохожу @@error
,
Я хочу зафиксировать эту ошибку no at frontend
то есть.
catch (SqlException ex)
{
if ex.number==2627
MessageBox.show("Duplicate value cannot be inserted");
}
Я хочу эту функциональность. которые не могут быть достигнуты с помощью повышения уровня. Я не хочу давать пользовательское сообщение об ошибке на задней панели.
RAISEERROR должен возвращаться ниже указанной ошибки, когда я передаю ErrorNo для броска в catch
Msg 2627, Level 14, State 1, Procedure spOTest_DomainInsert,
Строка 14 Нарушение ограничения UNIQUE KEY 'UK_DomainCode'. Не удается вставить дублирующий ключ в объекте 'Tags.tblDomain. Заявление завершено.
EDIT:
Что может быть недостатком использования блока catch try, если я хочу, чтобы исключение обрабатывалось во фронте, учитывая хранимую процедуру, содержит несколько запросов, которые необходимо выполнить
Ответы
Ответ 1
Ниже приведен пример полнофункционального чистого кода для отката ряда операторов, если произошла ошибка и сообщить об ошибке.
begin try
begin transaction;
...
commit transaction;
end try
begin catch
declare @ErrorMessage nvarchar(max), @ErrorSeverity int, @ErrorState int;
select @ErrorMessage = ERROR_MESSAGE() + ' Line ' + cast(ERROR_LINE() as nvarchar(5)), @ErrorSeverity = ERROR_SEVERITY(), @ErrorState = ERROR_STATE();
rollback transaction;
raiserror (@ErrorMessage, @ErrorSeverity, @ErrorState);
end catch
Ответ 2
SQL 2012 вводит инструкцию throw:
http://msdn.microsoft.com/en-us/library/ee677615.aspx
Если оператор THROW указан без параметров, он должен появиться внутри блока CATCH. Это вызывает поднятие исключенного исключения.
BEGIN TRY
BEGIN TRANSACTION
...
COMMIT TRANSACTION
END TRY
BEGIN CATCH
ROLLBACK TRANSACTION;
THROW
END CATCH
Ответ 3
Я думаю, что ваш выбор:
- Не поймайте ошибку (пусть она пузырится вверх)
- Поднимите пользовательский
В какой-то момент SQL, вероятно, представит команду ререйза или способность поймать только определенные ошибки. Но пока используйте обходной путь. К сожалению.
Ответ 4
Повторяя внутри блока 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)
Ответ 5
Вы не можете: только двигатель может выдавать ошибки меньше 50000. Все, что вы можете сделать, это выбросить исключение, которое выглядит так...
См. мой ответ здесь, пожалуйста
Вопрос здесь использовал транзакции на стороне клиента, чтобы делать то, что он хотел, я думаю, это немного глупо...
Ответ 6
Хорошо, это обходной путь...: -)
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(), вы получите фактический номер ошибки, который вы хотите, и покажите соответствующий номер.
int errorNumber=(int)command.ExecuteScalar();
if(errorNumber=<SomeNumber>)
{
MessageBox.Show("Some message");
}
Надеюсь, что это поможет,
РЕДАКТИРОВАТЬ: - Просто примечание. Если вы хотите получить количество затронутых записей и попытаться использовать ExecuteNonQuery, вышеупомянутое решение может не сработать для вас. В противном случае я думаю, что это подойдет вам. Сообщите мне.
Ответ 7
Как остановить выполнение в хранимой процедуре после возникновения ошибки и вывести ошибку обратно в вызывающую программу, чтобы следовать за каждым оператором, который может вызвать ошибку с помощью этого кода:
If @@ERROR > 0
Return
Я был удивлен, узнав, что выполнение в хранимой процедуре может продолжаться после ошибки - не понимая, это может привести к некоторому трудному отслеживанию ошибок.
Этот тип обработки ошибок параллелирует (pre.Net) Visual Basic 6. С нетерпением ждем команды Throw в SQL Server 2012.
Ответ 8
Учитывая, что вы еще не переехали на 2012 год, одним из способов реализации буферизации исходного кода ошибки является использование части текстового сообщения исключения, которое вы выбрали (бросок) из блока catch. Помните, что он может содержать некоторую структуру, например XML-текст для вашего кода вызывающего абонента для анализа в блоке catch.
Ответ 9
Вы также можете создать хранимую процедуру-оболочку для этих сценариев, когда вы хотите, чтобы оператор 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'
Ответ 10
С точки зрения дизайна, какова точка бросания исключений с исходными номерами ошибок и пользовательскими сообщениями? В какой-то мере он нарушает контракт интерфейса между приложениями и базой данных.
Если вы хотите поймать исходные ошибки и обработать их в более высоком коде, не обрабатывайте их в базе данных. Затем, когда вы поймаете исключение, вы можете изменить сообщение, представленное пользователю, на все, что хотите. Я бы этого не сделал, потому что он делает ваш код базы данных "не прав". Как говорили другие, вы должны определить набор собственных кодов ошибок (выше 50000) и бросить их вместо этого. Затем вы можете блокировать проблемы целостности ( "Дублировать значения не допускаются" ) отдельно от потенциальных бизнес-проблем - "Почтовый индекс недействителен", "Не найдено строк, соответствующих критериям" и т.д.