Подтвердить что ты не робот

SqlException улов и обработка

Q: Есть ли лучший способ обработки SqlExceptions?

Нижеприведенные примеры основаны на интерпретации текста в сообщении.

Eg1: У меня есть существующий try catch для обработки, если таблица не существует.
Игнорируйте тот факт, что я могу проверить, существует ли таблица в первую очередь.

try
{
    //code
}
catch(SqlException sqlEx)
{
        if (sqlEx.Message.StartsWith("Invalid object name"))
        {
            //code
        }
        else
            throw;
}

Eg2: без try catch, отображающего исключение с повторяющимся ключом

if (sqlEx.Message.StartsWith("Cannot insert duplicate key row in object"))

Решение: начало моего SqlExceptionHelper

//-- to see list of error messages: select * from sys.messages where language_id = 1033 order by message_id
public static class SqlExceptionHelper
{
    //-- rule: Add error messages in numeric order and prefix the number above the method

    //-- 208: Invalid object name '%.*ls'.
    public static bool IsInvalidObjectName(SqlException sex)
    { return (sex.Number == 208); }

    //-- 2601: Cannot insert duplicate key row in object '%.*ls' with unique index '%.*ls'. The duplicate key value is %ls.
    public static bool IsDuplicateKey(SqlException sex)
    { return (sex.Number == 2601); }
}
4b9b3361

Ответ 1

В SqlException есть свойство

Ответ 2

Вид, вид. См. Причина и разрешение ошибок двигателя базы данных

class SqllErrorNumbers
{ 
   public const int BadObject = 208;
   public const int DupKey = 2627;
}

try
{
   ...
}
catch(SqlException sex)
{
   foreach(SqlErrorCode err in sex.Errors)
   {
      switch (err.Number)
      {
      case SqlErrorNumber.BadObject:...
      case SqllErrorNumbers.DupKey: ...
      }
   }
}

Проблема заключается в том, что хороший DAL-слой будет TRY/CATCH внутри T-SQL (хранимые процедуры) с таким шаблоном, как Обработка исключений и вложенные транзакции, Увы, блок T-SQL TRY/CATCH не может поднять исходный код ошибки, ему придется поднять новую ошибку с кодом выше 50000. Это делает проблему с клиентской стороной проблемой. В следующей версии SQL Server существует новая конструкция THROW, которая позволяет повторно собрать исходное исключение из блоков catch T-SQL.

Ответ 3

Лучше использовать коды ошибок, вам не нужно разбираться.

try
{
}
catch (SqlException exception)
{
    if (exception.Number == 208)
    {

    }
    else
        throw;
}

Как узнать, что нужно использовать 208:

select message_id
from sys.messages
where text like 'Invalid object name%'

Ответ 4

Если вы хотите, чтобы список сообщений об ошибках встречался на сервере Sql, вы можете видеть с помощью

SELECT *
FROM master.dbo.sysmessages

Ответ 5

Если вы ищете лучший способ справиться с SQLException, есть пара вещей, которые вы могли бы сделать. Во-первых, Spring.NET делает что-то похожее на то, что вы ищете (я думаю). Вот ссылка на то, что они делают:

http://springframework.net/docs/1.2.0/reference/html/dao.html

Кроме того, вместо просмотра сообщения вы можете проверить код ошибки (sqlEx.Number). Казалось бы, это лучший способ определить, какая ошибка произошла. Единственная проблема заключается в том, что возвращаемый номер ошибки может отличаться для каждого поставщика базы данных. Если вы планируете переключать поставщиков, вы вернетесь к его обработке так, как вы, или создадите слой абстракции, который переводит эту информацию для вас.

Вот пример парня, который использовал код ошибки и файл конфигурации для перевода и локализации удобных сообщений об ошибках:

https://web.archive.org/web/20130731181042/http://weblogs.asp.net/guys/archive/2005/05/20/408142.aspx

Ответ 6

В MS SQL 2008 мы можем отображать поддерживаемые сообщения об ошибках в таблице sys.messages

SELECT * FROM sys.messages

Ответ 7

Для тех из вас, кто знает, кто может выбросить SQL-ошибку при подключении к БД с другого компьютера (например, при загрузке формы), вы обнаружите, что при первой настройке datatable в С#, которая указывает на SQL серверную базу данных, которая установит соединение следующим образом:

this.Table_nameTableAdapter.Fill(this.DatabaseNameDataSet.Table_name);

Вам может потребоваться удалить эту строку и заменить ее чем-то другим, как традиционная строка соединения, как указано в MSDN и т.д.

http://www.connectionstrings.com/sql-server-2008

Ответ 8

Вы можете оценить на основе по типу серьезности. Примечание. Чтобы использовать это, вы должны быть подписаны на OnInfoMessage

conn.InfoMessage += OnInfoMessage;
conn.FireInfoMessageEventOnUserErrors = true;

Тогда ваш OnInfoMessage будет содержать:

foreach(SqlError err in e.Errors) {
//Informational Errors
if (Between(Convert.ToInt16(err.Class), 0, 10, true)) {
    logger.Info(err.Message);
//Errors users can correct.
} else if (Between(Convert.ToInt16(err.Class), 11, 16, true)) {
    logger.Error(err.Message);
//Errors SysAdmin can correct.
} else if (Between(Convert.ToInt16(err.Class), 17, 19, true)) {
    logger.Error(err.Message);
//Fatal Errors 20+
} else {
    logger.Fatal(err.Message);
}}

Таким образом, вы можете оценить степень тяжести, а не номер ошибки и быть более эффективным. Вы можете найти более подробную информацию о серьезности здесь.

private static bool Between( int num, int lower, int upper, bool inclusive = false )
{
    return inclusive
        ? lower <= num && num <= upper
        : lower < num && num < upper;
}

Ответ 9

Я сначала работаю с кодом, С# 7 и сущностью framework 6.0.0.0. он работает для меня

Add()
{
     bool isDuplicate = false;
     try
     {
       //add to database 
     }
     catch (DbUpdateException ex)
     {
       if (dbUpdateException.InnerException != null)
       {
          var sqlException = dbUpdateException.InnerException.InnerException as SqlException;
          if(sqlException == null)
             isDuplicate = IsDuplicate(sqlException);
       } 
     }
     catch (SqlException ex)
     {
        isDuplicate = IsDuplicate(ex);
     }  
     if(isDuplicate){
       //handle here
     }
}

bool IsDuplicate(SqlException sqlException)
{
    switch (sqlException.Number)
    {
        case 2627:
            return true;
        default:
            return false;
    }
}

N.B: мой запрос для добавления элемента в db находится в другом проекте (слое)