SqlException вылов и обработка - PullRequest
58 голосов
/ 03 июня 2011

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

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

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

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

Eg2: без перехвата, показывающего исключение повторяющегося ключа

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); }
}

Ответы [ 9 ]

125 голосов
/ 03 июня 2011

SqlException имеет свойство Number , которое вы можете проверить.Для повторяющейся ошибки номер 2601.

catch (SqlException e)
{
   switch (e.Number)
   {
      case 2601:
         // Do something.
         break;
      default:
         throw;
   }
 }

Чтобы получить список всех ошибок SQL с вашего сервера, попробуйте следующее:

 SELECT * FROM sysmessages

Обновление

Теперь это можно упростить в C # 6.0

catch (SqlException e) when (e.Number == 2601)
{
   // Do something.
}
20 голосов
/ 03 июня 2011

Вроде, вроде. См. Причина и разрешение ошибок ядра СУБД

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 не может вызвать исходный код ошибки, он должен вызвать ошибку new , с кодом выше 50000. Это делает обработку на стороне клиента проблемой. В следующей версии SQL Server появилась новая конструкция THROW , которая позволяет повторно вызывать исходное исключение из блоков перехвата T-SQL.

7 голосов
/ 03 июня 2011

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

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

    }
    else
        throw;
}

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

select message_id
from sys.messages
where text like 'Invalid object name%'
4 голосов
/ 21 июня 2012

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

SELECT *
FROM master.dbo.sysmessages
1 голос
/ 15 апреля 2013

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

SELECT * FROM sys.messages
1 голос
/ 03 июня 2011

Если вы ищете лучший способ справиться с 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

0 голосов
/ 11 декабря 2017

Сначала я работаю с кодом, C # 7 и структурой сущностей 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;
    }
}

NB: мой запрос на добавление элемента в БД находится в другом проекте (слое)

0 голосов
/ 31 августа 2016

Вы можете оценить на основе в зависимости от типа серьезности.Обратите внимание, чтобы использовать это, вы должны быть подписаны на 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;
}
0 голосов
/ 01 марта 2013

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

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

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

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

...