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); }
}
Ответы
Ответ 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
). Казалось бы, это лучший способ определить, какая ошибка произошла. Единственная проблема заключается в том, что возвращаемый номер ошибки может отличаться для каждого поставщика базы данных. Если вы планируете переключать поставщиков, вы вернетесь к его обработке так, как вы, или создадите слой абстракции, который переводит эту информацию для вас.
Вот пример парня, который использовал код ошибки и файл конфигурации для перевода и локализации удобных сообщений об ошибках:
Ответ 6
В MS SQL 2008 мы можем отображать поддерживаемые сообщения об ошибках в таблице sys.messages
SELECT * FROM sys.messages
Ответ 7
Для тех из вас, кто знает, кто может выбросить SQL-ошибку при подключении к БД с другого компьютера (например, при загрузке формы), вы обнаружите, что при первой настройке datatable в С#, которая указывает на SQL серверную базу данных, которая установит соединение следующим образом:
this.Table_nameTableAdapter.Fill(this.DatabaseNameDataSet.Table_name);
Вам может потребоваться удалить эту строку и заменить ее чем-то другим, как традиционная строка соединения, как указано в MSDN и т.д.
Ответ 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 находится в другом проекте (слое)