Захват конкретного исключения
Как я могу поймать конкретное исключение с помощью С#?
В моей базе данных есть уникальный индекс для некоторых столбцов.
когда пользователь вставляет двойную запись, это исключение было выбрано:
Невозможно вставить повторяющуюся строку ключа в объект 'dbo.BillIdentity' с уникальным index 'IX_BillIdentity'. утверждение завершено.
Как я могу поймать это исключение?
В настоящее время я проверяю этот код:
catch (Exception ex) {
if (ex.Message.Contains("Cannot insert duplicate key row in object 'dbo._BillIdentity' with unique index 'IX__BillIdentity")) {
string ScriptKey = "$(function() {ShowMessage('Error');});";
ScriptManager.RegisterStartupScript(Page, GetType(), "script", ScriptKey, true);
}
}
Я думаю, что его плохой код запаха.
Есть ли лучший способ?
Ответы
Ответ 1
Вы не указали тип генерируемого исключения, но вы можете поймать этот конкретный тип исключения. Например:
catch (DuplicateKeyException e) {
...
}
Возможно, для этой ошибки не будет конкретного типа исключения, но если вам нужно поймать что-то довольно общее, например SqlException
, вы можете искать более подробную информацию внутри самого класса. Например, в SqlException
есть свойство Errors
, где вы можете посмотреть более подробную информацию о каждой из (возможно, нескольких) ошибок на стороне базы данных. Каждый SqlError
имеет свойство Number
, которое даст тип ошибки. Вы всегда можете вернуться к сообщению, если вам абсолютно необходимо, но тогда вам нужно знать о возможности изменения сообщения для разных культур и т.д.
Обратите внимание, что если вы действительно не обрабатываете исключение, вы должны, вероятно, изменить его:
catch (SqlException e) {
if (CheckWeCanHandle(e)) {
// Mess with the ScriptManager or whatever
} else {
throw;
}
}
Ответ 2
Обрабатывать SqlException
только в этом случае.
[изменить]
Чтобы проверить дублирующее ключевое исключение на сервере MS SQL:
try
{
// try to insert
}
catch (SqlException exception)
{
if (exception.Number == 2601) // Cannot insert duplicate key row in object error
{
// handle duplicate key error
return;
}
else
throw; // throw exception if this exception is unexpected
}
Изменить:
Откуда берутся 2601?
select *
from sys.messages
where text like 'Cannot insert duplicate key%'
Возврат:
message_id language_id severity is_event_logged text
----------- ----------- -------- --------------- ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
2601 1033 14 0 Cannot insert duplicate key row in object '%.*ls' with unique index '%.*ls'. The duplicate key value is %ls.
Используя exception.Number
и ссылаясь на представление sys.messages, вы можете обрабатывать любое конкретное исключение MS SQL.
Ответ 3
Я только что выбрал проект, где кто-то пошел по этому маршруту:
Catch ex As SqlException
Select Case ex.Number
Case 2601
...
Обратите внимание на следующее (из sys.messages в SQL Server):
2601 - Невозможно вставить повторяющуюся строку ключа в объект "%. * ls" с уникальным индексом "%. * ls".
Но как насчет этого..?
2627 - Нарушение ограничения% ls '%. * ls'. Невозможно вставить дублирующий ключ в объект "%. * Ls".
Я просто потратил некоторое время на поиск именно этой проблемы.
А что, если мы изменим поставщика БД? Предположительно 2601 не является абсолютно универсальным... Это воняет, ИМО. И если вы имеете дело с этим в своем слое презентации, я думаю, что есть большие вопросы, которые нужно задать.
Если это должен быть механизм выбора, зарыть его глубоко, глубоко в DAL, и пусть пользовательское исключение просачивается вверх. Таким образом, изменения в хранилище данных (или, в идеале, этот механизм) имеют гораздо более ограниченную область действия, и вы можете обрабатывать случай последовательно без каких-либо вопросов на уровне презентации.
В настоящее время я склоняюсь к выполнению легкого SELECT для ID в открытом соединении и вообще избегаю исключения.
Ответ 4
Вы можете только поймать SqlException для стартеров
catch (SqlException ex) {
if (ex.Message.Contains("Cannot insert duplicate key row in object 'dbo._BillIdentity' with unique index 'IX__BillIdentity")) {
string ScriptKey = "$(function() {ShowMessage('Error');});";
ScriptManager.RegisterStartupScript(Page, GetType(), "script", ScriptKey, true);
}
}
Ответ 5
Как описано здесь, вы можете использовать фильтры исключений. Пример:
try
{ /* your code here */ }
catch (SqlException sqlex) when (sqlex.Number == 2627)
{ /* handle the exception */ }
Ответ 6
Рабочий код для фильтра только дубликат исключения первичного ключа исключения
using System.Data.Entity.Infrastructure;
using System.Data.SqlClient;
.........
try{
abc...
}
catch (DbUpdateException ex)
{
if (ex.InnerException.InnerException is SqlException sqlEx && sqlEx.Number == 2601)
{
return ex.ToString();
}
else
{
throw;
}
}