Как восстановить одно и то же исключение в 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) и бросить их вместо этого. Затем вы можете блокировать проблемы целостности ( "Дублировать значения не допускаются" ) отдельно от потенциальных бизнес-проблем - "Почтовый индекс недействителен", "Не найдено строк, соответствующих критериям" и т.д.