Перехват исключений в качестве ожидаемого управления потоком выполнения программы? - PullRequest
11 голосов
/ 25 сентября 2008

Я всегда чувствовал, что ожидать исключения на регулярной основе и использовать их в качестве логики потока было плохой вещью. Исключения выглядят так, как будто они должны быть " исключение ". Если вы ожидаете и планируете исключение, это может означать, что ваш код должен быть реорганизован, по крайней мере, в .NET ...
Тем не мение. Недавний сценарий заставил меня задуматься. Я опубликовал это на msdn некоторое время назад, но я бы хотел больше обсудить это, и это идеальное место!

Итак, скажем, у вас есть таблица базы данных, которая имеет внешний ключ для нескольких других таблиц (в случае, когда изначально возникла дискуссия, на нее указывали 4 внешних ключа). Вы хотите разрешить пользователю удалять, но только если нет ссылок на внешние ключи; Вы НЕ хотите каскадного удаления.
Обычно я просто проверяю, есть ли ссылки, и, если они есть, я информирую пользователя, а не делаю удаление. Очень легко и просто написать, что в LINQ связанные таблицы являются членами объекта, поэтому в Section.Projects и Section.Categories и т. Д. Удобно набирать с помощью intellisense и всех ...
Но дело в том, что LINQ затем должен поразить потенциально все 4 таблицы, чтобы увидеть, есть ли какие-либо строки результатов, указывающие на эту запись, и попадание в базу данных, очевидно, всегда является относительно дорогой операцией.

Руководитель этого проекта попросил меня изменить его, чтобы просто перехватить SqlException с кодом 547 (ограничение внешнего ключа) и обработать его таким образом.

Я был ...
устойчив .

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

На каком-то уровне это все еще кажется мне неправильным .

Что вы, ребята, думаете об ожидающих и намеренно обработанных исключениях? Это нормально, когда кажется, что это будет более эффективно, чем проверка заранее? Это больше сбивает с толку следующего разработчика, смотрящего на ваш код, или меньше сбивает с толку? Насколько это безопаснее, поскольку база данных может знать о новых ограничениях внешнего ключа, о которых разработчик может и не подумать, чтобы добавить проверку? Или это вопрос перспективы того, что именно вы считаете лучшей практикой?

Ответы [ 8 ]

7 голосов
/ 25 сентября 2008

Ваше лидерство абсолютно верно. Исключения - не только один раз в ситуации «голубой луны», но и специально для сообщения о других результатах, кроме ожидаемых.

В этом случае проверка внешнего ключа все равно будет выполняться, а исключения - это механизм, с помощью которого вы можете получать уведомления.

Чего НЕ следует делать, так это перехватывать и подавлять исключения с помощью общего оператора catchall. Выполнение мелкозернистой обработки исключений - именно поэтому исключения были разработаны в первую очередь.

4 голосов
/ 25 сентября 2008

Вау,

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

Краткий ответ "да", но это может зависеть.

  • У нас есть несколько приложений, в которых много бизнес-логики, связанной с SQL-запросами (не мой дизайн Gov!). Если это так, то сложнее убедить руководство в том, что оно «уже работает».
  • В этой ситуации это действительно имеет большое значение? Так как это еще одна поездка через провод и обратно. Делает ли сервер много, прежде чем он поймет, что он не может продолжаться (т. Е. Если есть последовательность транзакций, которые происходят в вашем действии, то он падает на полпути, теряя время?).
  • Имеет ли смысл сначала выполнять проверку в пользовательском интерфейсе? Помогает ли это в вашем приложении? Если это обеспечивает лучший пользовательский опыт? (т.е. я видел случаи, когда вы проходите через несколько шагов в мастере, он запускается, а затем падает, когда у него есть вся информация, необходимая для переключения после шага 1).
  • Является ли параллелизм проблемой? Возможно ли, что запись может быть удалена / отредактирована или что-то еще до того, как ваш коммит произойдет (как в классическом File.Exists бу-бу).

На мой взгляд:

Я бы сделал оба . Если я могу быстро потерпеть неудачу и обеспечить лучший пользовательский опыт, отлично. Любые ожидаемые SQL (или любые другие) исключения должны быть в любом случае перехвачены и соответствующим образом возвращены.

Я знаю, что существует консенсус, что исключения не должны использоваться для других случаев, кроме исключительных обстоятельств , но помните, что мы пересекаем границы приложения здесь, ничего не ожидаем . Как я уже сказал, это похоже на File.Exists, в этом нет никакого смысла, его можно удалить, прежде чем получить к нему доступ.

2 голосов
/ 26 сентября 2008

Хороший вопрос. Тем не менее, я нахожу ответы ... страшно!
Исключением является разновидность GOTO.
Мне не нравится использовать исключения таким образом, потому что это приводит к коду спагетти.
Просто как тот.

2 голосов
/ 25 сентября 2008

Я думаю, что вы правы, исключения должны использоваться только для обработки неожиданных результатов, здесь вы используете исключение для обработки возможного ожидаемого результата, вы должны разобраться с этим делом явно, но все же поймать исключение, чтобы показать возможную ошибку.

Если только этот случай не будет обработан во всем коде, я бы поддержал вас. Проблема производительности должна быть поднята только в том случае, если это действительно проблема, то есть она будет зависеть от размера этих таблиц и количества раз, когда эта функция используется.

1 голос
/ 23 ноября 2010

Мне не нравится видеть исключения повсюду в программе, но в этом случае я бы использовал механизм исключений.

Даже если вы тестируете в LINQ, вам придется перехватывать исключение, если кто-то вставляет дочернюю запись, пока вы тестируете целостность с помощью LINQ. Так как вы все равно должны проверить исключение, зачем дублировать код?

Другой момент заключается в том, что такого рода «короткие» исключения не вызывают проблем с обслуживанием и не затрудняют чтение вашей программы. У вас будет попытка, вызов SQL для удаления и выгода - все это в пределах 10 строк кода вместе. Намерение очевидно.

Не то же самое, что генерировать исключение, которое должно быть перехвачено. 5 вызовов процедур в верху стека, с проблемами в том, что все объекты между ними были обработаны правильно (освобождены) правильно.

Исключения не всегда являются волшебным ответом, но я бы не чувствовал себя неправильно, используя их в этой ситуации.

Мои два цента,

Yves

1 голос
/ 25 сентября 2008

Я бы порекомендовал вызвать хранимую процедуру, которая проверяет наличие каких-либо зависимостей, а затем удаляет их, если их нет. Таким образом, проверка целостности сделана.

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

1 голос
/ 25 сентября 2008

Поймать определенное SqlException - правильная вещь. Это механизм, с помощью которого SQL Server сообщает о состоянии внешнего ключа. Даже если вы предпочитаете использовать механизм исключений по-другому, именно так SQL Server делает это.

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

1 голос
/ 25 сентября 2008

Нет ничего плохого в том, что вы делаете. Исключения не обязательно являются «исключительными». Они существуют, чтобы позволить вызывающим объектам иметь детальную обработку ошибок в зависимости от их потребностей.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...