Перехват исключений в качестве ожидаемого управления потоком выполнения программы?

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

Тем не мение. Недавний сценарий заставил меня задуматься. Я опубликовал это на MSDN некоторое время назад, но яЯ хотел бы больше поговорить об этом, и это идеальное место!



Так скажиу нас есть таблица базы данных, у которой есть внешний ключ для нескольких других таблиц (в случае, когда изначально возникла дискуссия, на нее указывали 4 внешних ключа). Вы хотите разрешить пользователю удалять, но только если нет ссылок на внешние ключи; ты неТ хочу каскадно удалить.

Обычно я просто проверяю, есть ли ссылки, и, если они есть, я информирую пользователя, а не делаю удаление. Это'Очень легко и просто написать, что в LINQ связанные таблицы являются членами объекта, поэтому в Section.Projects и Section.Categories и т. д. удобно набирать с помощью intellisense и всего ...

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



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



Я был...

упорная.



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

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

Таким образом, они выиграли, и я изменил это.



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



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

Ответы на вопрос(8)

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

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

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

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

Хороший вопрос Тем не менее, я нахожу ответы ... страшно!

Исключением является разновидность GOTO.

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

Просто как тот.

 Peter Gfader11 окт. 2009 г., 03:30
+1 за GOTO! тот'ооочень верно
Решение Вопроса

Вот это да,

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

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

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

По моему мнению:

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

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

 Rob Cooper25 сент. 2008 г., 19:45
Но дело не только в производительности или параллелизме. Это предположение, что это проблема. Как я уже сказал, делайте и то, и другое, если это обеспечивает лучший пользовательский опыт, но вы должны обрабатывать исключения в любом случае.
 Grank25 сент. 2008 г., 19:43
Это's очень мелкое применение; в клиентеВ текущей среде большая часть вставки будет выполняться только одним человеком. На максимуме я думаю 25 пользователей. Так что параллелизм нене проблема, производительность неэто проблема, этоидеальное время для обсуждения стандартов;)

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

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

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

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

 Rob Cooper25 сент. 2008 г., 19:42
Полностью согласен с вами на этом одном левике, люди, которые отвечают этим "исключительные обстоятельства " не хватает смысла (см. мой пост).
 Grank25 сент. 2008 г., 19:33
Я очень согласен с вашей редакцией. Конкретно только SqlException 547 ловится
 Grank25 сент. 2008 г., 19:31
Ну, это ожидаемый результат, которыйС проблемой. Гораздо чаще, чем нет, будут дети.

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

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

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

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

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

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

Ив

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

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

Ваш ответ на вопрос