Почему исключение типа SqlException не перехватывается try / catch SqlException? - PullRequest
0 голосов
/ 06 апреля 2019

У меня есть следующий код:

    try
    {
        Data.CreateUserAndAccount.ExecuteProcedure(accountName, firstName, lastName, email, password);
        return String.Empty;
    }
    catch (SqlException databaseError)
    {
        string result = IdentifyError(databaseError);
        return result;
    }
    catch  (Exception)
    {
        throw;
    }

Я намеренно выбрасываю исключения SQL, нарушая уникальный ключ. Однако исключение отлавливается Exception, а не SqlException. Когда я проверяю детали InnerException, исключение имеет тип System.Data.SqlClient.SqlException.

InnerException Details

Почему исключение SQL перехватывается только общим Exception?

Ответы [ 2 ]

4 голосов
/ 06 апреля 2019

Проблема в том, что вы пытаетесь поймать SqlException, но это не тип исключения: это InnerException.

Если user10954641 прав, и это UpdateException, вы можете просто поймать это:

try
{
}
catch (UpdateException e)
{
}

Если это другое исключение, то перехватите любой тип исключения, который на самом деле выдается. В качестве альтернативы вы можете условно перехватывать исключения, для которых InnerException равен SqlException:

try
{
}
catch (Exception e) when (e.InnerException is SqlException)
{
}

Если вам интересно, почему catch (SqlException) не работает, рассмотрите следующий код:

public void ThrowException()
{
    try
    {
        MakeDatabaseCall();
    }
    catch (Exception e)
    {
        throw new Exception("Uh oh!", e);
    }
}

public void MakeDatabaseCall()
{
    throw new SqlException();
}

Вызов ThrowException() в конечном итоге приведет к форме ошибки MakeDatabaseCall(), но тип исключения не будет SqlException, потому что мы заключаем его в другое исключение (в данном случае базовый класс исключения): Exception. Но, поскольку мы передаем исключение, сгенерированное MakeDatabaseCall() в конструктор, наше "О, о!" исключение будет содержать SqlException в своем поле InnerException.

Когда вы используете try / catch(ExceptionType e), вы указываете .NET, что шаблон соответствует совпадению, прежде чем решить, какой оператор catch ввести. Для иллюстрации, два фрагмента кода ниже приблизительно эквивалентны :

try
{
}
catch(SqlException e)
{
    //catches an SqlException
}

и

try
{
}
catch(Exception e) when (e is SqlException)
{
    //catches an SqlException
}

Очевидно, что в нашем примере ThrowException, Exception не является производным от SqlException, поэтому catch (SqlException e) не будет совпадать.

0 голосов
/ 06 апреля 2019

Оказывается, исключение имеет тип EntityCommandExecutionException, который получен из DataException.

Изначально я намеревался выполнить некоторую логику на SqlException.Number, поэтому я пытался поймать SqlException.

Однако, чтобы решить эту проблему, поймайте DataException и затем приведите InnerException к SqlException:

try
{
    Data.CreateUserAndAccount.ExecuteProcedure(accountName, firstName, lastName, email, password);
    return String.Empty;
}
catch (DataException procedureError)
{
    SqlException sqlError = (SqlException)procedureError.InnerException;
    string result = IdentifyError(sqlError);
    return result;
}
...