有没有办法在违反约束时给出用户友好的错误消息

发布于 2024-11-08 07:54:03 字数 853 浏览 4 评论 0原文

假设我有列 Gender 和约束 CHECK( Gender IN ('F', 'M', 'OTHER'))
如果我不小心忘记在客户端处理这个问题,用户将看到类似
ORA-02290: 违反检查约束 (SYS_C099871244)
这对用户和维护或调试的开发人员来说都不是很有帮助

有没有办法提供开发人员定义的消息,例如(伪)Java的
assert Gender IN (0,1):'Gender must be F or M'

我能想到的唯一方法是将约束移至 BEFORE UPDATE OR INSERT 触发器,并在失败时执行 Raise_Application_Error (代码,my_message)。但我不喜欢它

编辑 具体原因列表,如评论中
1. 我真的很喜欢让逻辑尽可能接近数据
2. 对于最终用户而言,Raise_Application_Error 消息与应用程序消息无法区分
3.即使绕过应用程序访问数据,开发人员也会看到不错的消息
4.将约束移动到触发器很丑陋(是吗?),所以我必须找到与 Raise_Application_Error 不同的东西

EDIT2 1.5 年后,在我离开与数据库相关的工作后,我终于意识到,我真正不喜欢这个 - 代码重复 。我必须在服务器和客户端上重复完全相同的逻辑。最有可能的是,用两种不同的语言。并使它们保持同步。这太丑了。

尽管答案清楚地表明,我对此无能为力。所以现在是我成为好公民并最终接受答案的时候了(抱歉,只是忘记了这一点)。

Say I have column Gender and constraint CHECK( Gender IN ('F', 'M', 'OTHER')).
If I accidentally forgot to handle this on client side, user will see smth like
ORA-02290: check constraint (SYS_C099871244) violated
which is not very helpful nor for user, nor for developer who maintains or debug

Is there way to provide developer-defined message like (pseudo)Java's
assert Gender IN (0,1):'Gender must be F or M'

The only way I can think of is to move constraints to the BEFORE UPDATE OR INSERT trigger and on failure do Raise_Application_Error( code, my_message ). But I don't like it

EDIT
List of specific reasons, as per in the comments
1. I really like to keep logic as close to data as possible
2. For end user Raise_Application_Error message is indistinguishable from application message
3. Developers will see nice message, even if access data bypassing application
4. moving constraints to triggers is ugly (is it?), so I have to find smth different from Raise_Application_Error

EDIT2
1,5 years later, and after I've left db-related job, it has finally occured to me, what I really don't like about this - code duplication. I have to repeat exactly same logic on server and on client side. Most likely, in 2 different languages. And keep them in sync. This is just ugly.

Though as answers clearly indicate, there is nothing I can about this. So it's time for me to be good citizen and finally accept an answer (sorry, just forgot about that).

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

北恋 2024-11-15 07:54:03

约束是数据库用来保护自己免受错误应用程序,的影响,而不是来自用户的影响。

这意味着应用程序应该捕获约束违规,并可能进行清理以呈现给用户。我认为没有这样做的应用程序在某种程度上是有缺陷的。

我说“可能”是因为您的应用程序(至少对于这种情况)永远不会看到这种情况发生。几乎可以肯定,它应该使用下拉式有限选择控件来实现类似的功能。如果它使用组合框或(震惊,恐怖)自由格式的文本输入字段,则需要重新定义。

这意味着违规永远不会发生,除非应用程序和约束在某个时刻不同步。但是,早在客户接触您的应用程序之前,就应该在测试中发现这一点。


为了回答您的实际问题,Oracle 发出的有关约束违规的消息无法更改。您能做的最好的事情就是明智地命名您的约束,以便最终用户能够理解。

但我仍然认为向用户呈现问题是应用程序层的责任,而不是数据库层的责任。

Constraints are what databases use to protect themselves from errant applications, not from users.

That means that constraint violations should be captured by the application and possibly cleaned up for presentation to the user. I'd consider an application which didn't do that to be deficient in some manner.

I say 'possibly' since your application (at least for this case) should never see that happen. It should almost certainly be using a drop down limited-choice control for something like that. If it used a combo-box or (shock, horror) a free-format text entry field, it would need to be redefined.

That would mean that the violation would never occur unless, of course, the application and the constraint get out of sync at some point. But that's something that should be caught in testing, long before a customer ever gets their grubby little hands on your application.


To answer your actual question, the messages that come out of Oracle for constraint violations cannot be changed. The best you can do is to name your constraints intelligently so that it may make sense to an end user.

But I still maintain that this presentation of problems to a user is a responsibility of the application layer, not the database layer.

南笙 2024-11-15 07:54:03

如果您正在寻找一种方法来告诉 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可以提供像这样的包和表作为标准,但也许由于在实践中系统中的错误处理有许多不同的要求,所以它通常被认为不够有用。

If you are looking for a way to tell Oracle always to replace the exception message "ORA-02290: check constraint (SYS_C099871244) violated" by another message like "ORA-20001: Gender must be F or M", then the answer is: no, it can't be done.

What you can do is provide a solution that can be used by developers in their code something like this:

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

The error_pkg.handle_exception procedure would parse the Oracle exception message and extract the name of the constraint (if it was a constraint violation) and lookup that constraint name in a cross reference table to get the required message, then use raise_application_error to re-raise the exception with the new message.

I suppose Oracle could offer a package and table like this as standard, but perhaps since in practice there are many different requirements for error handling in system, it isn't considered to be generally useful enough.

橘亓 2024-11-15 07:54:03

简而言之:
据我所知,没有办法捕获用于自定义处理的 Oracle 错误。但我认为无论如何你都不应该尝试这样做。


长版:
你的理由背后的意图是好的,但是......

我真的很喜欢让逻辑尽可能接近数据

逻辑应该尽可能接近数据,这是事实;但这不符合条件 - 这不是逻辑,这是识别已定义逻辑异常的代码的表示,并且表示不应与数据或逻辑层混合(错误消息的范围涵盖从客户端到服务器端的每个部分;还要考虑翻译、一致更新、更轻松的消息管理和概述等...)

对于最终用户,Raise_Application_Error 消息是
与应用程序无法区分
留言

True,但反之亦然,因此不是特别相关 - 如果您有数据库错误代码、应用程序错误代码的中央存储库,并且错误处理将对其进行处理,那么哪一层出现错误是不相关的(对于最终用户)消息。此外,从长远来看,尚不清楚它是否会节省您的任何工作。

即使访问数据绕过,开发人员也会看到不错的消息
应用

确实如此,对于直接访问数据库的开发人员来说,会有更好的错误消息。这里仍然有一些评论适用 - 在复杂的系统中,不应允许绕过应用程序层(即使对于开发人员也是如此);如果允许的话,您会期望开发人员知道在哪里从约束名称查找错误消息(错误代码和消息的中央存储库应该/将维护在同一个数据库中)

将约束移动到触发器是丑陋的
(是吗?),所以我必须找到一些东西
与 Raise_Application_Error 不同

它在某种意义上是丑陋的,因为它是表现形式,不应该出现在 DDL 中。此外,如果通过触发器完成,它会导致不合理的(?)性能损失(不确定它有多大,也不知道它可以完成得有多优雅)。

注意:总而言之,我确实同意能够挂钩 DBMS 错误处理将是一个很好的功能。

然而,错误处理和错误消息处理具有以下属性

  • 需要可维护(理论上,可以通过在信息模式中存储自定义错误消息来干净地完成此操作,但 SQL 标准没有指定这一点,因此这纯粹是理论评论 - 实际上为此,您必须拥有自己的表)

,更重要的是,

  • 错误消息处理是上下文敏感的(并且错误处理程序将从数据客户端的角度获得最多的信息 - 有时相同错误代码可能需要不同的呈现方式、不同的消息)

In short:
No way of catching oracle errors for custom handling that I know of. However I don't think you should be trying to do that anyway.


Long version:
The intentions behind your reasons are good, however...

I really like to keep logic as close to data as possible

Logic should be as close to data as possible, that is true; however this does not qualify - this is not logic, this is presentation of codes that identify exceptions to already defined logic, and presentation should not be mixed with data or logic layers (the domain of error messages spans over every part of the system; from client side to server side, also think about translating, consistent updates, easier management and overview of the messages, etc...)

For end user Raise_Application_Error message is
indistinguishable from application
message

True, but the reverse is valid as well and therefore not particularly relevant - if you have central repository of DB error codes, application error codes, and error handling will process it then it is irrelevant (for end user) which layer is presenting error messages. Also, long term, it is not clear that it would save you any work.

Developers will see nice message, even if access data bypassing
application

This is true, for developers accessing DB directly there would be nicer error messages. Still a few comments apply here - in complex systems bypassing the application layer should not be allowed (even for developers); if that would be allowed you would expect devs to know where to look up the error messages from the constraint names (central repository of error codes and messages should/would be maintained in the same db)

moving constraints to triggers is ugly
(is it?), so I have to find smth
different from Raise_Application_Error

It is ugly in a sense that it is presentation and should not be in DDL. Also, it incurs unjustified(?) performance penalties if done through triggers (not sure how big, nor how elegant it could be done).

Note: All in all I do agree that it would be a nice feature to have possibility to hook into DBMS error handling.

However, error handling and error message processing has following properties

  • needs to be maintainable (this, theoretically, could be done cleanly by storing custom error messages in the information schema, but SQL standard does not specify that so this is purely theoretical comment - in practice you will have to have your own tables for such purposes)

and, even more importantly

  • error message processing is context sensitive (and error handler would be most informed from the point of view of the data client - sometimes same error code might need different presentation, different message)
北斗星光 2024-11-15 07:54:03

无论约束是向客户端提出还是记录在文件中以供支持人员进行(潜在)分析,您都应该获得更有用的消息。

如果你命名你的约束,它会变得更有帮助。

我会去做类似的事情

ALTER TABLE blah ADD CONSTRAINT blah_gender_ck CHECK ( Gender IN ('F', 'M', 'OTHER'));

Whether the constraint gets raised to the client or logged in a file for (potential) analysis by support, you should have a more useful message.

If you name your constraint it gets more helpful.

I'd go for something like

ALTER TABLE blah ADD CONSTRAINT blah_gender_ck CHECK ( Gender IN ('F', 'M', 'OTHER'));
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文