Есть ли способ дать удобное сообщение об ошибке при нарушении ограничения

Скажи у меня есть колонка Gender и ограничение CHECK( Gender IN ('F', 'M', 'OTHER')),
Если я случайно забуду обработать это на стороне клиента, пользователь увидит что-то вроде
ORA-02290: check constraint (SYS_C099871244) violated
что не очень полезно ни для пользователя, ни для разработчика, который поддерживает или отлаживает

Есть ли способ предоставить определенные разработчиком сообщения, такие как (псевдо)Java
assert Gender IN (0,1):'Gender must be F or M'

Единственный способ, о котором я могу подумать, - это перенести ограничения на триггер BEFORE UPDATE OR INSERT, а при сбое выполнить Raise_Application_Error( code, my_message ), Но мне это не нравится

РЕДАКТИРОВАТЬ Список конкретных причин, как в комментариях
1. Мне действительно нравится держать логику как можно ближе к данным
2. Для конечного пользователя сообщение Raise_Application_Error неотличимо от сообщения приложения
3. Разработчики увидят приятное сообщение, даже если доступ к данным в обход приложения
4. перемещение ограничений на триггеры - это ужасно (правда?), Поэтому я должен найти что-то отличное от Raise_Application_Error

РЕДАКТИРОВАТЬ 21,5 года спустя, и после того, как я оставил работу, связанную с БД, мне наконец пришло в голову, что мне действительно не нравится в этом - дублирование кода. Я должен повторить ту же логику на сервере и на стороне клиента. Скорее всего, на 2 разных языках. И держать их в синхронизации. Это просто безобразно

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

4 ответа

Решение

Если вы ищете способ заставить Oracle всегда заменять сообщение об исключении "ORA-02290: проверка ограничения (SYS_C099871244) нарушено" другим сообщением, например "ORA-20001: Пол должен быть F или M", тогда ответ: нет, это не может быть сделано

Что вы можете сделать, так это предоставить решение, которое разработчики могут использовать в своем коде, примерно так:

...
begin
    insert into emp (empno, gender) values (p_empno, p_gender);
exception
    when others then
       error_pkg.handle_exception;
end;

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

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

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

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

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

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


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

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

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


Длинная версия:
Однако намерения, стоящие за вашими причинами, хороши...

Мне действительно нравится держать логику как можно ближе к данным

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

Для конечного пользователя сообщение Raise_Application_Error неотличимо от сообщения приложения

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

Разработчики увидят приятное сообщение, даже если доступ к данным в обход приложения

Это правда, для разработчиков, получающих доступ к БД напрямую, будут появляться более приятные сообщения об ошибках. Еще несколько комментариев здесь применимы - в сложных системах обход уровня приложения запрещен (даже для разработчиков); если это будет разрешено, вы ожидаете, что разработчики будут знать, где искать сообщения об ошибках из имен ограничений (центральный репозиторий кодов ошибок и сообщений должен / должен поддерживаться в том же БД)

перемещение ограничений на триггеры ужасно (правда?), поэтому я должен найти что-то отличное от Raise_Application_Error

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

Примечание. В целом я согласен с тем, что было бы неплохо иметь возможность подключиться к обработке ошибок СУБД.

Однако обработка ошибок и обработка сообщений об ошибках имеют следующие свойства

  • должен быть поддерживаемым (теоретически это можно было бы сделать чисто путем хранения пользовательских сообщений об ошибках в информационной схеме, но в стандарте SQL это не указано, так что это чисто теоретический комментарий - на практике для этих целей вам понадобятся собственные таблицы))

и, что еще важнее

  • обработка сообщений об ошибках является контекстно-зависимой (и обработчик ошибок будет наиболее информирован с точки зрения клиента данных - иногда один и тот же код ошибки может потребовать другого представления, другого сообщения)

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

Если вы называете свое ограничение, это становится более полезным.

Я бы пошел на что-то вроде

ALTER TABLE blah ADD CONSTRAINT blah_gender_ck CHECK ( Gender IN ('F', 'M', 'OTHER'));
Другие вопросы по тегам